import Arena from './arena.mjs'; import Inspector from './inspector.mjs'; // one per page const TICK_BUTTON_SELECTOR = '#tick'; const TICK_RATE_SELECTOR = '#tick-rate-select'; const RUN_BUTTON_SELECTOR = '#run'; async function loaded() { Arena.register(); Inspector.register(); const robos = [{ worker: new Worker('robo.mjs', { type: 'module' }), lastTick: undefined, heading: 0, speed: 0, speedx: 0, speedy: 0, }].map(r => document.querySelector(Arena.name).randStart(r)); robos.forEach((robo, i) => { robo.worker.onmessage = e => { const { kind, res, trans } = e.data; switch (kind) { case 'compile': if (res) { document.querySelector(Arena.name).render(robos); document.querySelectorAll(Inspector.name)[i].render(trans, true); } break; case 'tick': robo.lastTick = document.timeline.currentTime; [robo.x, robo.y] = document.querySelector(Arena.name).clamp(Arena.radius, robo.x + robo.speedx, robo.y + robo.speedy); document.querySelector(Arena.name).render(robos, robo.lastTick); robo.heading = trans.vars.heading; robo.speed = trans.vars.speed; [robo.speedx, robo.speedy] = [ Math.cos(2 * Math.PI * robo.heading / 360), Math.sin(2 * Math.PI * robo.heading / 360) ].map(x => robo.speed * x); document.querySelectorAll(Inspector.name)[i].render(trans); break; default: console.error('invalid message from robo worker', e.data); } }; robo.worker.onerror = e => { console.error('error in roboWorker', e); }; }); document.querySelectorAll(Inspector.name).forEach((elt, i) => { elt.addEventListener(Inspector.compileRequest, e => { console.debug('compiling', e.detail.text); robos[i].worker.postMessage({ kind: 'compile', text: e.detail.text }); }); }); document.querySelector(TICK_BUTTON_SELECTOR).onclick = e => { console.debug('tick clicked', e); robos.forEach(robo => robo.worker.postMessage({ kind: 'tick' })); }; document.querySelector(TICK_RATE_SELECTOR).onchange = e => { console.debug('tick rate changed', e, Number(e.target.value)); document.querySelector(Arena.name).tickMS = 1_000 / e.target.value; } document.querySelectorAll(TICK_RATE_SELECTOR).forEach(elt => elt.onchange({ target: elt })); let blinkenRun = false; function renderFrame(t) { if (!blinkenRun) { return; } self.requestAnimationFrame(renderFrame); document.querySelector(Arena.name).render(robos, t); } function timeout() { if (!blinkenRun) { return } self.setTimeout(timeout, document.querySelector(Arena.name).tickMS); robos.forEach(robo => robo.worker.postMessage({ kind: 'tick' })); } document.querySelector(RUN_BUTTON_SELECTOR).onclick = e => { console.debug('blinken clicked', e); blinkenRun = !blinkenRun; if (blinkenRun) { e.currentTarget.classList.remove('halten'); e.currentTarget.classList.add('blinken'); e.currentTarget.querySelector('title').textContent = 'halten'; setTimeout(timeout); renderFrame(document.timeline.currentTime); } else { e.currentTarget.classList.remove('blinken'); e.currentTarget.classList.add('halten'); e.currentTarget.querySelector('title').textContent = 'blinken'; document.querySelector(Arena.name).invalidateFPS(); } } } document.addEventListener('DOMContentLoaded', loaded);