You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
3.9 KiB
JavaScript
144 lines
3.9 KiB
JavaScript
let gameState = {
|
|
running: false,
|
|
pixelSize: 0,
|
|
lastReported: null,
|
|
frameTimes: [],
|
|
frames: 0,
|
|
width: 0,
|
|
height: 0,
|
|
canvas: null,
|
|
ctx: null,
|
|
gameExports: null
|
|
}
|
|
|
|
const initialMessage = "Click the board above to start simulation"
|
|
|
|
export async function setup(wasmModule) {
|
|
gameState.gameExports = wasmModule.exports
|
|
|
|
const canvas = gameState.canvas = document.querySelector('#game')
|
|
gameState.ctx = gameState.canvas.getContext("2d")
|
|
gameState.ctx.fillStyle = getComputedStyle(gameState.canvas).getPropertyValue('--foreground')
|
|
|
|
const pixelSize = gameState.pixelSize = parseInt(canvas.getAttribute('data-pixelsize') || '2')
|
|
gameState.width = Math.floor(parseInt(canvas.width) / pixelSize)
|
|
gameState.height = Math.floor(parseInt(canvas.height) / pixelSize)
|
|
|
|
initialize()
|
|
drawBoard()
|
|
|
|
const frameTimesElem = document.getElementById('frameTimes')
|
|
const resetButton = document.getElementById('reset')
|
|
|
|
frameTimesElem.innerText = initialMessage
|
|
|
|
gameState.canvas.addEventListener('click', () => {
|
|
if (!gameState.running) {
|
|
if (frameTimesElem.innerText === initialMessage)
|
|
frameTimesElem.innerText = 'Starting...'
|
|
|
|
gameState.running = true
|
|
frameLoop()
|
|
} else {
|
|
gameState.running = false;
|
|
gameState.frameTimes = []
|
|
gameState.lastReported = null
|
|
}
|
|
})
|
|
|
|
resetButton.addEventListener('click', () => {
|
|
gameState.running = false
|
|
gameState.frameTimes = []
|
|
gameState.lastReported = null
|
|
frameTimesElem.innerText = initialMessage
|
|
initialize()
|
|
drawBoard()
|
|
})
|
|
}
|
|
|
|
export async function onThemeChange() {
|
|
drawBoard()
|
|
gameState.ctx.fillStyle = getComputedStyle(gameState.canvas).getPropertyValue('--foreground')
|
|
}
|
|
|
|
export async function cleanup() {
|
|
gameState.running = false
|
|
}
|
|
|
|
function initialize() {
|
|
const { gameExports, width, height } = gameState
|
|
|
|
gameExports.initializeBoard(width, height)
|
|
|
|
for (let row = 0; row < height; row++) {
|
|
for (let column = 0; column < width; column++) {
|
|
const filled = Math.random() > .5;
|
|
gameExports.setValueAtPosition(row, column, filled ? 1 : 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
function frameLoop() {
|
|
const { gameExports, running, frameTimes } = gameState
|
|
|
|
if (!gameState.lastReported)
|
|
gameState.lastReported = performance.now()
|
|
|
|
if (!running) return
|
|
|
|
const beforeTick = performance.now()
|
|
gameExports.tick()
|
|
const afterTick = performance.now()
|
|
drawBoard()
|
|
const afterDraw = performance.now()
|
|
|
|
// Push raw frame time
|
|
frameTimes.push(afterDraw - beforeTick)
|
|
|
|
if (frameTimes.length >= 10) {
|
|
const averageFrame = (frameTimes.reduce((a, b) => a + b) / frameTimes.length).toFixed(2);
|
|
|
|
const lastReported = gameState.lastReported
|
|
const current = gameState.lastReported = performance.now()
|
|
const tenFrameTime = (current - lastReported) / 1000
|
|
const fps = Math.floor(10 / tenFrameTime).toFixed(0)
|
|
gameState.frameTimes = []
|
|
|
|
const pagesUsed = gameExports.getPagesUsed()
|
|
|
|
document.getElementById('frameTimes').innerHTML =
|
|
`Frames per second: ${fps}<br/>
|
|
Milliseconds per frame: ${averageFrame}<br/>
|
|
Memory allocated: ${pagesUsed} pages (${pagesUsed * 64} KiB)`
|
|
}
|
|
|
|
console.log(`tick took ${afterTick - beforeTick}ms`)
|
|
console.log(`draw took ${afterDraw - afterTick}ms`)
|
|
|
|
requestAnimationFrame(frameLoop)
|
|
}
|
|
|
|
function drawBoard() {
|
|
const { gameExports, width, height, pixelSize, ctx, canvas } = gameState
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
ctx.beginPath()
|
|
for (let row = 0; row < height; row++) {
|
|
for (let column = 0; column < width; column++) {
|
|
const alive = gameExports.getValueAtPosition(row, column)
|
|
|
|
if (!alive) continue
|
|
|
|
const x = column * pixelSize
|
|
const y = row * pixelSize
|
|
|
|
ctx.moveTo(x, y)
|
|
ctx.lineTo(x + pixelSize, y)
|
|
ctx.lineTo(x + pixelSize, y + pixelSize)
|
|
ctx.lineTo(x, y + pixelSize)
|
|
ctx.lineTo(x, y)
|
|
}
|
|
}
|
|
ctx.fill()
|
|
}
|