diff --git a/js/consts.mjs b/js/consts.mjs index 5cb31bd..9f4c718 100644 --- a/js/consts.mjs +++ b/js/consts.mjs @@ -24,8 +24,8 @@ export const TIP_ANGLE = 0.25; export const TIP_SPEED = 0.03; // Ship flight mechanics. Speed measured in units per tick. export const FUEL_BURN_RATE = 0.01; -export const THRUST_POWER = 0.007; -export const TURN_POWER = 0.05; +export const THRUST_POWER = 0.004; +export const TURN_POWER = 0.07; // Distance at which an orbited planet will not be considered a parent body. export const MAX_PARENT_CELESTIAL_DISTANCE = 120; // Ship editing. diff --git a/js/data.mjs b/js/data.mjs index c30ef00..2190d22 100644 --- a/js/data.mjs +++ b/js/data.mjs @@ -11,7 +11,7 @@ export const modules = { mass: 2, connectivity: [false, false, true, false], capacity: 2, - rotation: 0.1 + rotation: 1 } }, fuel: { @@ -29,13 +29,12 @@ export const modules = { light: { name: 'Light Main Thruster', tooltip: 'Powerful enough to lift a small ship, but not much ' + - 'more. Not very efficient.', + 'more.', type: 'thruster', id: 'light', mass: 2, connectivity: [true, false, false, false], - thrust: 10, - isp: 200 + thrust: 10 } }, connector: { diff --git a/js/game/control.mjs b/js/game/control.mjs index 232a6cb..0eb37c0 100644 --- a/js/game/control.mjs +++ b/js/game/control.mjs @@ -1,8 +1,8 @@ import * as input from '../input.mjs'; import * as events from './events.mjs'; -import * as player from './player.mjs'; import * as graphics from '../graphics/index.mjs'; import * as inventory from './inventory.mjs'; +import {playerShip} from '../world/index.mjs'; import {state} from './index.mjs'; export const mapping = { @@ -36,15 +36,15 @@ export function tick() { function tickPlaying() { if (held[mapping.thrust]) { - player.ship.applyThrust({ forward: 1 }); + playerShip.applyThrust({ forward: 1 }); } if (held[mapping.left]) { - player.ship.applyThrust({ turnLeft: 1 }); + playerShip.applyThrust({ turnLeft: 1 }); } if (held[mapping.right]) { - player.ship.applyThrust({ turnRight: 1 }); + playerShip.applyThrust({ turnRight: 1 }); } if (pressed[mapping.inventory]) { @@ -67,4 +67,6 @@ function tickEditing() { if (pressed[mapping.exitEdit]) { events.endEditing(); } + + if (pressed['KeyX']) throw new Error(); } diff --git a/js/game/edit.mjs b/js/game/edit.mjs index f70d8fc..454540b 100644 --- a/js/game/edit.mjs +++ b/js/game/edit.mjs @@ -13,6 +13,7 @@ export let height = 0; export let position = [0, 0]; export let bounds = [0, 0, 0, 0]; export let message = ''; +export let info = ''; export function init() { let ship = world.playerShip; @@ -38,6 +39,7 @@ function adjustSize() { let [sx, ex, sy, ey] = getBoundaries(); [width, height] = [ex - sx + margin * 2 + 1, ey - sy + margin * 2 + 1]; position = [sx - margin, sy - margin]; + getAttributes(); } export function end() { @@ -65,6 +67,35 @@ export function end() { return result; } +function getAttributes() { + let cargo = 0; + let fuel = 0; + let rotation = 0; + let mass = 0; + let thrust = 0; + + tiles.forEach(t => { + if (t.type === null) return; + if (t.type === 'fuel') { + fuel += t.module.fuelCapacity; + } else if (t.type === 'capsule') { + rotation += t.module.rotation; + cargo += t.module.capacity; + } else if (t.type === 'thruster') { + thrust += t.module.thrust; + } else if (t.type === 'gyroscope') { + rotation += t.module.rotation; + } + mass += t.module.mass; + }); + + info = 'Mass: ' + mass + '\n' + + 'Fuel capacity: ' + fuel + '\n' + + 'Thrust/mass ratio: ' + (thrust / mass).toFixed(1) + '\n' + + 'Rotation speed: ' + (rotation / mass * 100).toFixed(1) + '\n' + + 'Cargo capacity: ' + cargo; +} + function validate() { let capsulesFound = 0; let thrustersFound = 0; diff --git a/js/game/events.mjs b/js/game/events.mjs index 3785497..9c69b82 100644 --- a/js/game/events.mjs +++ b/js/game/events.mjs @@ -1,21 +1,23 @@ import * as game from './index.mjs'; import * as graphics from '../graphics/index.mjs'; import * as world from '../world/index.mjs'; -import * as player from './player.mjs'; import * as inventory from './inventory.mjs'; import * as particle from '../world/particle.mjs'; import * as edit from './edit.mjs'; import * as audio from './audio.mjs'; export let shipLanded = false; +export let score = 0; let notification = null; let notLife = 0; +let landedPlanets = new Set(); + function notify(message) { if (notification === null) return; notification.text = message; - notLife = 60; + notLife = 80; } export function tick() { @@ -33,11 +35,21 @@ export function startGame() { graphics.perspective.focusPlayer(); } -export function landShip() { +export function landShip(planet) { shipLanded = true; + if (!landedPlanets.has(planet)) { + newPlanet(planet); + } game.state.landed = true; } +function newPlanet(planet) { + let value = (planet.radius + 30) | 0; + landedPlanets.add(planet); + score += value; + notify('Landed on new planet: +' + value); +} + export function launchShip() { shipLanded = false; game.state.landed = false; @@ -95,5 +107,7 @@ export function tossItem() { export function collectItem(type, id) { inventory.addItem(type, id); audio.play('itemPickup'); + score += 20; + notify('Collected module: +20'); return true; } diff --git a/js/game/index.mjs b/js/game/index.mjs index d99d9be..966493b 100644 --- a/js/game/index.mjs +++ b/js/game/index.mjs @@ -6,7 +6,6 @@ import * as inventory from './inventory.mjs'; import * as world from '../world/index.mjs'; import * as events from './events.mjs'; import * as control from './control.mjs'; -import * as player from './player.mjs'; import * as edit from './edit.mjs'; export let state; @@ -45,7 +44,6 @@ export function changeView(view) { state.editing = false; state.paused = false; world.init(); - player.init(); inventory.init(); } } diff --git a/js/game/player.mjs b/js/game/player.mjs deleted file mode 100644 index 1f60798..0000000 --- a/js/game/player.mjs +++ /dev/null @@ -1,8 +0,0 @@ -import * as world from '../world/index.mjs'; -import * as inventory from './inventory.mjs'; - -export let ship; - -export function init() { - ship = world.playerShip; -} diff --git a/js/graphics/gui.mjs b/js/graphics/gui.mjs index 0e9b1d1..ec4c79a 100644 --- a/js/graphics/gui.mjs +++ b/js/graphics/gui.mjs @@ -7,7 +7,6 @@ export function render() { } function renderElement(element) { - //console.log(element.options); if (element.options.draw) { if (element.type === 'frame') renderFrame(element); if (element.type === 'image') renderImage(element); @@ -93,7 +92,7 @@ function renderItemButton(element) { context.drawImage(element.image, ox, oy, dw, dh); } - if (element.quantity > 1) { // CHANGE TO 1 + if (element.quantity > 1) { context.textAlign = 'right'; context.textBaseline = 'bottom'; context.fillStyle = '#fff'; @@ -110,6 +109,6 @@ function renderEdit(element) { function renderInventory(element) { context.globalAlpha = 0.1; context.fillStyle = '#541'; - context.fillRect(...element.shape); + context.fillRect(...element.parent.shape); context.globalAlpha = 1; } diff --git a/js/gui/edit.mjs b/js/gui/edit.mjs index f37fb9d..417f1f3 100644 --- a/js/gui/edit.mjs +++ b/js/gui/edit.mjs @@ -57,7 +57,7 @@ export default class GuiEdit extends GuiElement { this.parent.options.drawChildren = this.active; if (!this.active) return; - this.textElements.info.text = edit.message; + this.textElements.info.text = edit.info; [this.tileWidth, this.tileHeight] = [edit.width, edit.height]; } diff --git a/js/gui/modules.mjs b/js/gui/modules.mjs index f30e2a0..8f40ba9 100644 --- a/js/gui/modules.mjs +++ b/js/gui/modules.mjs @@ -10,6 +10,7 @@ import GuiText from './text.mjs'; import GuiInventory from './inventory.mjs'; import * as events from '../game/events.mjs'; import {state} from '../game/index.mjs'; +import * as world from '../world/index.mjs'; export function root() { return new GuiFrame(0, 0, canvas.width, canvas.height, { @@ -51,11 +52,41 @@ export function game() { editButton.options.disabled = state.editing && editMessage !== ''; if (state.editing) { editButton.text = 'Finish'; + if (editMessage !== '') editButton.text = '(' + editMessage + ')'; } else { editButton.text = 'Edit rocket'; } } + let fuel = new GuiText('', 0, 0, 0, 0, { + size: 14, + align: 'right', + valign: 'bottom' + }); + shadow.append(fuel); + fuel.posRelative({x: 1, y: 1}); + fuel.y -= 10; + fuel.x -= 10; + fuel.tick = () => { + let ship = world.playerShip; + fuel.text = 'Fuel: ' + ship.fuel.toFixed(1) + '/' + + ship.maxFuel.toFixed(1); + }; + + let score = new GuiText('', 0, 0, 0, 0, { + size: 14, + align: 'left', + valign: 'bottom' + }); + shadow.append(score); + score.posRelative({x: 0, y: 1}); + score.y -= 10; + score.x += 10; + score.tick = () => { + score.text = 'Score: ' + events.score + }; + + let editShadow = root(); shadow.append(editShadow); editShadow.posRelative({x: 0.45, y: 0, w: 0.55, h: 0.6}); @@ -68,11 +99,12 @@ export function game() { let editInfoText = new GuiText('', 0, 0, 0, 0, { size: 12, - align: 'center' + align: 'right' }); editShadow.append(editInfoText); - editInfoText.posRelative({x: 0.5, y: 1}); + editInfoText.posRelative({x: 1, y: 1}); editInfoText.y += 5; + editInfoText.x -= 20; let editWarnText = new GuiText('', 0, 0, 0, 0, { size: 12, diff --git a/js/input.mjs b/js/input.mjs index b4f1d72..0a93bca 100644 --- a/js/input.mjs +++ b/js/input.mjs @@ -23,19 +23,17 @@ export function init() { }); window.addEventListener('keyup', event => { - keyCode.pressed[event.code] = false; keyCode.held[event.code] = false; - key.pressed[event.key] = false; key.held[event.key] = false; }); // Ṕ͕͖ẖ̨’̖̺͓̪̹n̼͇͔̯̝̖g̙̩̭͕ͅͅl̻̰͘u͎̥͍̗ͅi̼̞̪̩͚̜͖ ̫̝̻͚͟m͎̳̙̭̩̩̕g̟̤̬̮l̫̕w̶͚͈͚̟͔’͖n͏̝͖̞̺ͅa͏̹͓̬̺f̗̬̬̬̖̫͜h͙̘̝̱̬̗͜ ̼͎͖C̱͔̱͖ṭ̬̱͖h̵̰̼̘̩ùlh̙́u̪̫ ̪̺̹̙̯R̞͓̹̞’͍͎͉͎̦͙ͅl͇̠̮y̙̪̰̪͙̖e̢̩͉͙̼h̗͔̹̳ ̶w̨̼͍̝̭̣̣ͅg̶̳̦̳a̴͉̹͙̭̟ͅh͈͎̞̜͉́’̼̜̠͞n̲a̯g̮͚͓̝l̠ ̹̹̱͙̝f̧̝͖̱h̪̟̻͖̖t͎͘aͅg̤̘͜n̶͈̻̻̝̳ window.addEventListener('mousedown', event => { mouse.pressed[event.button] = !mouse.held[event.button]; mouse.held[event.button] = true; + tickAfterMouse = false; }); window.addEventListener('mouseup', event => { - mouse.pressed[event.button] = false; mouse.held[event.button] = false; }); diff --git a/js/world/body.mjs b/js/world/body.mjs index c9b93ab..a575adf 100644 --- a/js/world/body.mjs +++ b/js/world/body.mjs @@ -105,8 +105,8 @@ export default class Body { applyDirectionalForce(x, y, r) { let [vx, vy] = this.rotateVector(x, y); - this.xvel += vx; - this.yvel += vy; + this.xvel += vx / this.mass; + this.yvel += vy / this.mass; this.rvel += r / this.mass; } diff --git a/js/world/ship.mjs b/js/world/ship.mjs index 1f8e598..a9982d1 100644 --- a/js/world/ship.mjs +++ b/js/world/ship.mjs @@ -17,6 +17,11 @@ export default class Ship extends Body { this.landed = false; this.lastContactModule = null; this.poc = this.com; + this.maxFuel = 0; + this.fuel = 0; + this.rotationPower = 0; + this.cargoCapacity = 0; + this.thrust = 0; } get com() { @@ -56,8 +61,13 @@ export default class Ship extends Body { this.modules.forEach(m => m.reset()); - if (events.shipLanded != this.landed) - this.landed ? events.landShip() : events.launchShip(); + if (events.shipLanded != this.landed) { + if (this.landed) { + events.landShip(this.parentCelestial) + } else { + events.launchShip() + } + } } clearModules() { @@ -85,6 +95,23 @@ export default class Ship extends Body { let [lx, ly] = this.localCom; this.maxRadius = points.reduce((a, [bx, by]) => Math.max(Math.sqrt((bx - lx) ** 2 + (by - ly) ** 2), a), 0) + 1; + + this.maxFuel = 0; + this.rotationPower = 0; + this.cargoCapacity = 0; + + this.modules.forEach(m => { + if (m.type === 'fuel') { + this.maxFuel += m.data.fuelCapacity; + } else if (m.type === 'capsule') { + this.rotationPower += m.data.rotation; + this.cargoCapacity += m.data.capacity; + } else if (m.type === 'thruster') { + this.thrust += m.data.thrust; + } else if (m.type === 'gyroscope') { + this.rotationPower += m.data.rotation; + } + }); } colliding(point, radius) { @@ -158,8 +185,9 @@ export default class Ship extends Body { applyThrust({ forward = 0, left = 0, right = 0, back = 0, turnLeft = 0, turnRight = 0}) { - let thrustForce = -forward * consts.THRUST_POWER; + let thrustForce = -forward * consts.THRUST_POWER * this.thrust; let turnForce = (turnRight - turnLeft) * consts.TURN_POWER; + turnForce *= this.rotationPower; this.applyDirectionalForce(0, thrustForce, turnForce);