diff --git a/dist/audio/crash2.mp3 b/dist/audio/crash2.mp3 new file mode 100644 index 0000000..a9101fc Binary files /dev/null and b/dist/audio/crash2.mp3 differ diff --git a/js/assets.mjs b/js/assets.mjs index ccabc99..1e5672b 100644 --- a/js/assets.mjs +++ b/js/assets.mjs @@ -40,7 +40,9 @@ export const audio = { endEdit: 'release1.mp3', newPlanet: 'up2.mp3', engine: 'rocket2.ogg', - music: 'music2.mp3' + music: 'music2.mp3', + toss: 'thunk1.mp3', + crash: 'crash2.mp3' }; export async function init() { @@ -52,7 +54,7 @@ export async function init() { parse(images, str => { let img = new Image(); img.src = 'img/' + str; - promises.push(new Promise((res, rej) => { + promises.push(new Promise((res) => { img.addEventListener('load', res); })); return img; @@ -61,7 +63,7 @@ export async function init() { let audio = new Howl({ src: ['audio/' + str] }); - promises.push(new Promise((res, rej) => { + promises.push(new Promise((res) => { audio.once('load', res); })); return audio; diff --git a/js/consts.mjs b/js/consts.mjs index 47d44bc..fabe2f8 100644 --- a/js/consts.mjs +++ b/js/consts.mjs @@ -22,6 +22,7 @@ export const ZOOM_SPEED = 0.01; // Ship landing. Angle in radians. export const TIP_ANGLE = 0.25; export const TIP_SPEED = 0.03; +export const CRASH_SPEED = 0.7; // Ship flight mechanics. Speed measured in units per tick. export const FUEL_BURN_RATE = 0.3; export const THRUST_POWER = 0.004; diff --git a/js/game/control.mjs b/js/game/control.mjs index 53411e6..47fbc1b 100644 --- a/js/game/control.mjs +++ b/js/game/control.mjs @@ -26,7 +26,7 @@ export function tick() { if (state.editing) { tickEditing(); - } else if (state.playing) { + } else if (state.playing && !state.gameOver) { tickPlaying(); } @@ -36,6 +36,10 @@ export function tick() { } } + if (state.gameOver) { + audio.stop('engine'); + } + if (pressed[mapping.toggleMusic]) { audio.toggle('music'); } diff --git a/js/game/events.mjs b/js/game/events.mjs index 45457b5..0b9d747 100644 --- a/js/game/events.mjs +++ b/js/game/events.mjs @@ -32,7 +32,7 @@ function notify(message, time = 80) { export function tick() { if (notification === null) return; - if (notLife-- <= 0) + if (notLife-- <= 0 || game.state.gameOver) notification.text = ''; } @@ -70,6 +70,12 @@ export function launchShip() { game.state.landed = false; } +export function crash() { + audio.play('crash'); + particle.createCrash(world.playerShip) + game.state.gameOver = true; +} + export function toggleEdit() { if (game.state.editing) { endEditing(); @@ -122,6 +128,7 @@ export function tilePlacement() { export function tossItem() { particle.createItemToss(world.playerShip); + audio.play('toss'); } export function collectItem(type, id, name) { diff --git a/js/game/index.mjs b/js/game/index.mjs index db1cf98..853c2b4 100644 --- a/js/game/index.mjs +++ b/js/game/index.mjs @@ -16,7 +16,8 @@ export async function init() { playing: false, editing: false, paused: false, - inventory: false + inventory: false, + gameOver: false }; graphics.init(); @@ -24,8 +25,8 @@ export async function init() { gui.init(); input.init(); - //events.playMusic(); - events.startGame(); + events.playMusic(); + //events.startGame(); //tick(); return; diff --git a/js/graphics/world.mjs b/js/graphics/world.mjs index 78b5758..941c44e 100644 --- a/js/graphics/world.mjs +++ b/js/graphics/world.mjs @@ -46,6 +46,7 @@ function renderEntity(entity) { } function renderShip(ship) { + if (ship.crashed) return; context.save(); context.translate(...ship.com); context.rotate(ship.r); diff --git a/js/world/particle.mjs b/js/world/particle.mjs index b9f8d22..40ebd55 100644 --- a/js/world/particle.mjs +++ b/js/world/particle.mjs @@ -27,6 +27,37 @@ export function createEndEditBurst(ship) { } } +export function createCrash(ship) { + for (let i = 0; i < ship.mass + 3; i++) { + particles.add(new Particle(...ship.poc, { + color: '#f2e860', + lifetime: Math.random() * 50 + 40, + size: Math.random() * 0.2 + 0.2, + spray: 0.9, + gravity: true + })); + } + for (let i = 0; i < ship.mass + 3; i++) { + particles.add(new Particle(...ship.poc, { + color: '#f75722', + lifetime: Math.random() * 50 + 40, + size: Math.random() * 0.2 + 0.2, + spray: 0.5, + gravity: true + })); + } + for (let i = 0; i < ship.mass * 2 + 3; i++) { + particles.add(new Particle(...ship.poc, { + color: '#888', + lifetime: Math.random() * 30 + 55, + size: Math.random() * 0.5 + 0.4, + spray: 2, + friction: 0.9, + gravity: false + })); + } +} + export function createPickupBurst(ship, point) { for (let i = 0; i < 20; i++) { particles.add(new Particle(...point, { diff --git a/js/world/ship.mjs b/js/world/ship.mjs index 1aa5a30..ea593b7 100644 --- a/js/world/ship.mjs +++ b/js/world/ship.mjs @@ -22,6 +22,7 @@ export default class Ship extends Body { this.rotationPower = 0; this.cargoCapacity = 0; this.thrust = 0; + this.crashed = false; } get com() { @@ -48,7 +49,7 @@ export default class Ship extends Body { } tick() { - window.q = []; + if (this.crashed) return; if (!state.editing) this.tickMotion(); if (!this.landed) this.tickGravity(world.celestials); if (!state.editing) this.resolveCollisions(); @@ -151,10 +152,19 @@ export default class Ship extends Body { let dis = body.distanceTo({ com: p }); if (dis < body.radius + 0.5 + consts.EPSILON) { this.approach(body, dis - (body.radius + 0.5)); + this.moduleCollided(module); this.halt(); this.resolveCelestialCollision(p, body, module); - this.lastContactModule = module; this.poc = p; + this.lastContactModule = module; + } + } + + moduleCollided(module) { + let speed = Math.sqrt(this.xvel ** 2 + this.yvel ** 2); + if (module.type !== 'thruster' || speed > consts.CRASH_SPEED) { + events.crash(); + this.crashed = true; } }