summaryrefslogtreecommitdiff
path: root/level.js
blob: 360b91858e14277b191b1c5b50530824d3101b29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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}) ]);
}