From ad5e699c810e448dc24d06dec201b7867b9f5e06 Mon Sep 17 00:00:00 2001 From: sanine Date: Fri, 5 Jul 2024 22:58:00 -0500 Subject: add level.js --- level.js | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 level.js (limited to 'level.js') diff --git a/level.js b/level.js new file mode 100644 index 0000000..360b918 --- /dev/null +++ b/level.js @@ -0,0 +1,112 @@ +import { render } from './render.js'; + + +const X_START = '0.7t+sin(t)-6'; +const Y_START = '0.7t-6'; + +const PATH_LEN = 20; +const PATH_STEP = PATH_LEN/1000; + +const SLOW_RAMP = 1; +const FAST_RAMP = 0.01; + + +export function setupLevel(resources, home) { + const level = { + resources: resources.map(position => ({ position, collected: false })), + home, + running: false, + completed: false, + index: 0, + equations: { + x: math.compile(X_START), + y: math.compile(Y_START), + }, + }; + level.path = computePath(level.equations); + return level; +} + + +export function setupLevelUi(level, root, audio) { + const ui = { audio }; + + ui.rocketThrustAudio = document.getElementById('sfx-rocket-thrust'); + ui.rocketThrustSource = audio.createMediaElementSource(ui.rocketThrustAudio); + ui.rocketGain = audio.createGain(); + ui.rocketGain.gain.value = 0; + ui.rocketThrustSource.connect(ui.rocketGain).connect(audio.destination); + + ui.launchButton = document.createElement('input'); + ui.launchButton.type = 'button'; + ui.launchButton.value = 'Launch'; + ui.launchButton.onclick = () => { + level.running = false; + ui.rocketThrustAudio.play(); + ui.rocketGain.gain.setTargetAtTime(1, audio.currentTime, FAST_RAMP); + setTimeout(() => { level.running=true; stepLevel(ui, level, 0); }, 20); + } + + ui.xeq = document.createElement('input'); + ui.xeq.value = X_START; + ui.xeq.onchange = (e) => { + ui.rocketGain.gain.setTargetAtTime(0, audio.currentTime, FAST_RAMP); + setTimeout(() => ui.rocketThrustAudio.pause(), 50); + level.equations.x = math.compile(e.target.value); + level.running = false; + level.path = computePath(equations); + render(ui.ctx, level, 0); + }; + ui.xeq.onkeydown = ui.xeq.onchange; + ui.xeq.onkeyup = ui.xeq.onchange; + + ui.yeq = document.createElement('input'); + ui.yeq.value = Y_START; + ui.yeq.onchange = (e) => { + ui.rocketGain.gain.setTargetAtTime(0, audio.currentTime, FAST_RAMP); + setTimeout(() => ui.rocketThrustAudio.pause(), 50); + level.equations.y = math.compile(e.target.value); + level.running = false; + level.path = computePath(equations); + render(ui.ctx, level, 0); + }; + ui.yeq.onkeydown = ui.yeq.onchange; + ui.yeq.onkeyup = ui.yeq.onchange; + + root.appendChild(ui.xeq); + root.appendChild(ui.yeq); + root.appendChild(ui.launchButton); + + ui.canvas = document.createElement('canvas'); + ui.canvas.width = 600; + ui.canvas.height = 600; + root.appendChild(ui.canvas); + + ui.ctx = ui.canvas.getContext('2d'); + ui.ctx.translate(ui.canvas.width/2, ui.canvas.height/2) + ui.ctx.scale(ui.canvas.width/20, -ui.canvas.height/20); + + render(ui.ctx, level, 0); + return ui; +} + + +function stepLevel(ui, level, index) { + render(ui.ctx, level, index); + if (level.running && index < level.path.length-1) { + setTimeout(() => stepLevel(ui, level, index+1), 1); + } else { + level.running = false; + ui.rocketGain.gain.setTargetAtTime(0, ui.audio.currentTime, FAST_RAMP); + setTimeout(() => ui.rocketThrustAudio.pause(), 50); + render(ui.ctx, level, 0); + } +} + + +function computePath(equations, start, end, step) { + const ts = [...Array(Math.floor((PATH_LEN)/PATH_STEP)).keys()].map(k => PATH_STEP * k); + return ts.map(t => [ equations.x.eval({t}), equations.y.eval({t}) ]); +} + + -- cgit v1.2.1