diff options
Diffstat (limited to 'static/games/stallman-shooter/main.js')
| -rw-r--r-- | static/games/stallman-shooter/main.js | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/static/games/stallman-shooter/main.js b/static/games/stallman-shooter/main.js new file mode 100644 index 0000000..d3a3581 --- /dev/null +++ b/static/games/stallman-shooter/main.js @@ -0,0 +1,173 @@ +import * as state from '/static/games/stallman-shooter/state.js'; +import * as constants from '/static/games/stallman-shooter/constants.js'; + +let events = []; + +window.addEventListener('keydown', (e) => events.push(['keydown', e.key])); +window.addEventListener('keyup', (e) => events.push(['keyup', e.key])); + +const duration = 1000 / 60; + +function frame(ctx, st, events, textures) { + const new_bullets = []; + const count = st.count; + for (const enemy of st.enemies) { + new_bullets.push(...enemy.act(count)); + } + for (const bullet of st.bullets) { + state.straight_bullet_act(bullet); + } + for (const bullet of st.player_bullets) { + state.straight_bullet_act(bullet); + } + st.player.act(events); + if (count % st.player.fire_rate === 0) { + st.player_bullets.push(new state.PBullet(st.player.x, 0, st.player.y, -3.5)); + } + for (const bullet of st.bullets) { + if (state.overlaps(st.player, bullet)) { + return 'loss'; + } + } + for (const bullet of new_bullets) { + if (state.overlaps(st.player, bullet)) { + return 'loss'; + } + } + for (const enemy of st.enemies) { + for (const bullet of st.player_bullets) { + if (state.overlaps(enemy, bullet)) { + enemy.injure(bullet.damage()); + state.straight_bullet_delete(bullet); + } + } + } + st.enemies = st.enemies.filter((enemy) => enemy.health > 0); + if (st.enemies.length === 0) { + return 'win'; + } + st.bullets = st.bullets.filter((bullet) => !state.outside(bullet)); + st.bullets.push(...new_bullets); + st.player_bullets = st.player_bullets.filter((bullet) => !state.outside(bullet)); + + for (const bullet of st.player_bullets) { + state.draw(bullet, ctx, textures.pbullet); + } + for (const enemy of st.enemies) { + state.draw(enemy, ctx, textures.enemy); + } + state.draw(st.player, ctx, textures.player); + for (const bullet of st.bullets) { + state.draw(bullet, ctx, textures.ebullet); + } + ctx.strokeStyle = "red"; + ctx.strokeRect(0, 0, Math.round(st.enemies[0].health * constants.x_dim), 20); + st.count++; + return 'nothing'; +} + +async function get_bitmap(id) { + const image = document.getElementById(id); + await image.decode(); + return await window.createImageBitmap(image); +} + +async function get_player_bitmap() { + return get_bitmap('stallman'); +} + +async function get_enemy_bitmap() { + return get_bitmap('gates'); +} + +async function get_ebullet_bitmap() { + return get_bitmap('binary-blob'); +} + +async function get_pbullet_surface() { + return get_bitmap('player-pepp'); +} + +async function generic_message(ctx, image, okay) { + const bitmap = await get_bitmap(image); + while (true) { + await new Promise(window.requestAnimationFrame); + const ev = events; + events = []; + for (const event of ev) { + const [type, keycode] = event; + if (type === 'keydown' && keycode === okay) { + return; + } + } + ctx.drawImage(bitmap, 0, 0); + } +} + +async function introduction(ctx) { + await generic_message(ctx, 'introduction', 'Enter'); +} + +async function loss(ctx) { + await generic_message(ctx, 'loss', 'r'); +} + +async function victory(ctx) { + await generic_message(ctx, 'victory', 'r'); +} + +async function main() { + const canvas = document.getElementById('canvas'); + const ctx = canvas.getContext('2d'); + + await introduction(ctx); + + while (true) { + const st = new state.State(); + const [ + player_bitmap, + enemy_bitmap, + ebullet_bitmap, + pbullet_bitmap, + ] = await Promise.all([ + get_bitmap('stallman'), + get_bitmap('gates'), + get_bitmap('binary-blob'), + get_bitmap('player-pepp'), + ]); + const textures = { + player: player_bitmap, + enemy: enemy_bitmap, + ebullet: ebullet_bitmap, + pbullet: pbullet_bitmap, + }; + let last_frame_time = null; + let accumulator = 0; + game: while (true) { + const now = await new Promise(requestAnimationFrame); + if (last_frame_time !== null) { + accumulator += now - last_frame_time; + } + last_frame_time = now; + + while (accumulator >= duration) { + accumulator -= duration; + + ctx.fillStyle = "white"; + ctx.fillRect(0, 0, constants.x_dim, constants.y_dim); + const result = frame(ctx, st, events, textures); + events = []; + if (result === 'loss') { + await loss(ctx); + break game; + } + if (result === 'win') { + await victory(ctx); + break game; + } + } + } + } +} + +main() |
