diff --git a/js/consts.mjs b/js/consts.mjs index 845f5a0..c2b7860 100644 --- a/js/consts.mjs +++ b/js/consts.mjs @@ -8,6 +8,8 @@ // For fixing floating point rounding errors. export const EPSILON = 1e-8; +// Don't change these. +export const TAU = Math.PI * 2; // Unit length of sector. Only for internal representation. export const SECTOR_SIZE = 512; // G, G-boy, The big G, Mr. G, g's big brother, G-dog diff --git a/js/game/events.mjs b/js/game/events.mjs index d1f87a4..4bc95c3 100644 --- a/js/game/events.mjs +++ b/js/game/events.mjs @@ -8,15 +8,17 @@ import * as edit from './edit.mjs'; export let shipLanded = false; -let notification; +let notification = null; let notLife = 0; function notify(message) { + if (notification === null) return; notification.text = message; notLife = 60; } export function tick() { + if (notification === null) return; if (notLife-- <= 0) notification.text = ''; } diff --git a/js/graphics/index.mjs b/js/graphics/index.mjs index 03756ae..c1afa04 100644 --- a/js/graphics/index.mjs +++ b/js/graphics/index.mjs @@ -6,6 +6,8 @@ import {render as renderBackground} from './background.mjs'; import * as world from '../world/index.mjs'; import * as consts from '../consts.mjs'; +const TAU = consts.TAU; + export let canvas, context, tempCanvas, tempContext; export let perspective; export let trace = false; @@ -30,6 +32,10 @@ export function render() { context.fillStyle = '#000'; context.fillRect(0, 0, canvas.width, canvas.height); + context.beginPath(); + context.rect(0, 0, canvas.width, canvas.height); + context.clip(); + context.save(); perspective.tick(); perspective.transformRotate(); @@ -118,7 +124,7 @@ class Perspective { } get currentRotation() { - return this.interpolate(this.targetRotation, this.oldTarget); + return this.interpolateAngles(this.targetRotation, this.oldTarget); } get currentZoom() { @@ -131,15 +137,11 @@ class Perspective { } interpolateAngles(cur, old, x = this.transition) { - let a = cur % (Math.PI * 2); - let b = old % (Math.PI * 2); + return old + this.angleDifference(old, cur) * (1 - x); + } - let sum = a + b; - - if (sum > (Math.PI * 2) && sum < (Math.PI * 3)) - sum %= Math.PI; - - return sum / 2; + angleDifference(a, b) { + return Math.atan2(Math.sin(b - a), Math.cos(b - a)); } tick() { @@ -195,7 +197,7 @@ class Perspective { normalize() { this.targetZoom = Math.max(consts.MIN_ZOOM, Math.min(consts.MAX_ZOOM, this.targetZoom)); - this.targetRotation %= (Math.PI * 2); + this.targetRotation %= TAU; } transformRotate() { @@ -218,4 +220,8 @@ class Perspective { context.translate(tx + bw / 2, ty + bh / 2); context.scale(this.zoom, this.zoom); } + + normalizeAngle(a = this.r) { + return ((a % TAU) + TAU) % TAU; + } } diff --git a/js/world/body.mjs b/js/world/body.mjs index b065b4a..0cbf4f9 100644 --- a/js/world/body.mjs +++ b/js/world/body.mjs @@ -1,4 +1,4 @@ -import {GRAVITATIONAL_CONSTANT as G} from '../consts.mjs'; +import {GRAVITATIONAL_CONSTANT as G, TAU} from '../consts.mjs'; export default class Body { constructor(x, y, mass) { @@ -24,6 +24,14 @@ export default class Body { return Math.sqrt(this.xvel ** 2 + this.yvel ** 2); } + angleDifference(a, b) { + return Math.atan2(Math.sin(a - b), Math.cos(a - b)); + } + + normalizeAngle(a = this.r) { + return ((a % TAU) + TAU) % TAU; + } + getCelestialCollision(celestials) { let result = false; celestials.forEach(c => { @@ -51,6 +59,7 @@ export default class Body { (y * Math.cos(r) - x * Math.sin(r))]; } + // TODO: Remove and replace uses with `rotateVector`. relativeVector(x, y) { return this.rotateVector(x, y, this.r); } diff --git a/js/world/ship.mjs b/js/world/ship.mjs index 39aed32..97c456f 100644 --- a/js/world/ship.mjs +++ b/js/world/ship.mjs @@ -112,24 +112,27 @@ export default class Ship extends Body { } resolveCelestialCollision(pos, cel) { - // I don't even know why this works, don't touch it. - let theta = this.angleTo(...this.com, ...cel.com); - let angleToCom = this.angleTo(...this.com, ...pos); - let turnAngle = angleToCom - theta; - let checkAngle = theta - this.r - Math.PI / 2; + let celToCom = this.angleTo(...this.com, ...cel.com); + let celToPoc = this.angleTo(...pos, ...cel.com); + let pocToCom = this.angleTo(...this.com, ...pos); + + let turnAngle = this.angleDifference(celToPoc, pocToCom); + let checkAngle = this.angleDifference(celToPoc, this.r + Math.PI / 2); + let [force] = this.rotateVector(0, 1, turnAngle); - if (Math.abs(checkAngle) < consts.TIP_ANGLE) { - force *= -1; - } + + if (Math.abs(checkAngle) < consts.TIP_ANGLE) force *= -1; + let canLand = Math.abs(checkAngle) < 0.03 && Math.abs(this.rvel) < 0.001; if (canLand) { this.landed = true; this.rvel = 0; - this.r = theta - Math.PI / 2; + this.r = celToCom - Math.PI / 2; } - this.rvel -= force * consts.TIP_SPEED; + + this.rvel += force * consts.TIP_SPEED; } checkModuleCollision(module, body) {