summaryrefslogtreecommitdiffstats
path: root/site/main.mjs
blob: e2cdc3ed0ba708bcd655a6e7dc3e3212b0ac7625 (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
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);