summaryrefslogtreecommitdiff
path: root/level.js
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2024-07-05 22:58:00 -0500
committersanine <sanine.not@pm.me>2024-07-05 22:58:00 -0500
commitad5e699c810e448dc24d06dec201b7867b9f5e06 (patch)
tree745d92be7232e9a6139430cf9a392bfaaf5514ad /level.js
parent827c3a594b5138fb7e934791bdf66159ad80d5ec (diff)
add level.js
Diffstat (limited to 'level.js')
-rw-r--r--level.js112
1 files changed, 112 insertions, 0 deletions
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}) ]);
+}
+
+