From ba803b7ca93f4dcea532af2eef627bc764f4d433 Mon Sep 17 00:00:00 2001 From: asraelite Date: Sat, 3 Mar 2018 22:12:53 +0000 Subject: [PATCH] Improve planet collision --- js/graphics/index.mjs | 3 +-- js/graphics/world.mjs | 12 ++++++++---- js/world/body.mjs | 43 ++++++++++++++++++++++++++++++++++++------ js/world/celestial.mjs | 8 ++++---- js/world/module.mjs | 9 +++++++-- js/world/ship.mjs | 35 ++++++++++++++++++++++++++-------- js/world/spawn.mjs | 4 ++-- 7 files changed, 86 insertions(+), 28 deletions(-) diff --git a/js/graphics/index.mjs b/js/graphics/index.mjs index f727655..dce9f2a 100644 --- a/js/graphics/index.mjs +++ b/js/graphics/index.mjs @@ -58,8 +58,7 @@ class Perspective { } if (this.focus !== null) { - this.x = this.focus.x; - this.y = this.focus.y; + [this.x, this.y] = this.focus.com; } if (this.rotationFocus !== null) { diff --git a/js/graphics/world.mjs b/js/graphics/world.mjs index 748b5b9..93495ad 100644 --- a/js/graphics/world.mjs +++ b/js/graphics/world.mjs @@ -5,15 +5,19 @@ import * as world from '../world/index.mjs'; export function render() { world.celestials.forEach(renderCelestial); world.ships.forEach(renderShip); + if (typeof window.q !== 'undefined') { + context.fillStyle = 'red'; + } } function renderShip(ship) { context.save(); - context.translate(ship.x, ship.y); + context.translate(...ship.com); context.rotate(ship.r); - let [cx, cy] = ship.com; + let [cx, cy] = ship.localCom; + context.translate(-cx, -cy); ship.modules.forEach(m => { - context.drawImage(m.currentImage, m.x - cx, m.y - cy, 1, 1); + context.drawImage(m.currentImage, m.x, m.y, 1, 1); }); context.restore(); } @@ -23,6 +27,6 @@ const celestialImages = { } function renderCelestial(cel) { - context.drawImage(cel.image, cel.x - cel.radius, cel.y - cel.radius, + context.drawImage(cel.image, cel.x, cel.y, cel.diameter, cel.diameter); } diff --git a/js/world/body.mjs b/js/world/body.mjs index 09e5c72..08ddaef 100644 --- a/js/world/body.mjs +++ b/js/world/body.mjs @@ -12,6 +12,32 @@ export default class Body { this.mass = mass; } + get com() { + return [this.x, this.y]; + } + + get pos() { + return [this.x, this.y]; + } + + getWorldPoint(lx, ly) { + let [cx, cy] = this.localCom; + let [nx, ny] = this.rotateVector(lx - cx, ly - cy, this.r); + return [nx + this.x + cx, ny + this.y + cy]; + } + + getLocalPoint(wx, wy) { + let [lx, ly] = [wx - this.x, wy - this.y]; + let [cx, cy] = this.localCom; + let [nx, ny] = this.rotateVector(lx, ly, -this.r); + return [nx - cx, ny - cy]; + } + + rotateVector(x, y, r) { + return [(x * Math.cos(this.r) - y * Math.sin(this.r)), + (y * Math.cos(this.r) - x * Math.sin(this.r))]; + } + tickMotion() { this.x += this.xvel; this.y += this.yvel; @@ -22,19 +48,23 @@ export default class Body { tickGravity(bodies) { bodies.forEach(b => { let force = b.mass / this.mass / (this.distanceTo(b) ** 2) * G; - let angle = Math.atan2(b.y - this.y, b.x - this.x); + let [[ax, ay], [bx, by]] = [this.com, b.com]; + let angle = Math.atan2(by - ay, bx - ax); this.xvel += Math.cos(angle) * force; this.yvel += Math.sin(angle) * force; }); } distanceTo(body) { - return Math.max(Math.sqrt(((body.x - this.x) ** 2) + - ((body.y - this.y) ** 2)), 1); + let [[ax, ay], [bx, by]] = [this.com, body.com]; + let result = Math.max(Math.sqrt(((bx - ax) ** 2) + + ((by - ay) ** 2)), 1); + return result; } approach(body, distance) { - let angle = Math.atan2(body.y - this.y, body.x - this.x); + let [[ax, ay], [bx, by]] = [this.com, body.com]; + let angle = Math.atan2(by - ay, bx - ax); this.x += Math.cos(angle) * distance; this.y += Math.sin(angle) * distance; } @@ -45,8 +75,9 @@ export default class Body { } applyDirectionalForce(x, y, r) { - this.xvel += (x * Math.cos(this.r) - y * Math.sin(this.r)) / this.mass; - this.yvel += (y * Math.cos(this.r) - x * Math.sin(this.r)) / this.mass; + let [vx, vy] = this.rotateVector(x, y, r); + this.xvel += vx; + this.yvel += vy; this.rvel += r / this.mass; } } diff --git a/js/world/celestial.mjs b/js/world/celestial.mjs index d990198..b68cadd 100644 --- a/js/world/celestial.mjs +++ b/js/world/celestial.mjs @@ -15,12 +15,12 @@ export default class Celestial extends Body { this.image = imageArr[Math.random() * imageArr.length | 0]; } - tick() { - + get com() { + return [this.x + this.radius, this.y + this.radius]; } - get center() { - return [this.x + this.radius / 2, this.y + this.radius / 2]; + tick() { + } get diameter() { diff --git a/js/world/module.mjs b/js/world/module.mjs index 053fbfd..9675f7a 100644 --- a/js/world/module.mjs +++ b/js/world/module.mjs @@ -1,7 +1,7 @@ import {images as assets} from '../assets.mjs'; export default class Module { - constructor(x, y, { + constructor(x, y, ship, { name = 'Unnamed Module', type = 'block', id = 'unknown', @@ -16,6 +16,7 @@ export default class Module { this.name = name; this.type = type; this.mass = mass; + this.ship = ship; this.id = id; this.images = assets.modules[this.type][this.id]; // Fuel @@ -32,6 +33,10 @@ export default class Module { } } + get com() { + return this.ship.getWorldPoint(...this.localCom); + } + get currentImage() { if (this.type == 'thruster') { return this.power > 0 ? this.images.on : this.images.off; @@ -40,7 +45,7 @@ export default class Module { } } - get com() { + get localCom() { return [this.x + 0.5, this.y + 0.5]; } } diff --git a/js/world/ship.mjs b/js/world/ship.mjs index 3eb00be..93daf96 100644 --- a/js/world/ship.mjs +++ b/js/world/ship.mjs @@ -6,8 +6,14 @@ export default class Ship extends Body { constructor(x, y) { super(x, y, 0); - this.com = [0, 0]; + this.localCom = [0, 0]; this.modules = new Set(); + this.maxRadius = 0; + } + + get com() { + let [lx, ly] = this.localCom; + return [this.x + lx, this.y + ly]; } tick() { @@ -18,7 +24,7 @@ export default class Ship extends Body { } addModule(x, y, properties, options) { - let module = new Module(x, y, {...properties, ...options}); + let module = new Module(x, y, this, {...properties, ...options}); this.modules.add(module); this.refreshShape(); } @@ -30,24 +36,37 @@ export default class Ship extends Body { refreshShape() { let points = []; - this.modules.forEach(m => points.push([...m.com, m.mass])); + this.modules.forEach(m => points.push([...m.localCom, m.mass])); this.mass = points.reduce((a, [,,b]) => a + b, 0); - this.com = points.reduce(([ax, ay], [bx, by, bm]) => + this.localCom = points.reduce(([ax, ay], [bx, by, bm]) => [ax + bx * bm, ay + by * bm], [0, 0]) .map(x => x / this.mass); - window.q = points; + 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; } resolveCollisions() { world.celestials.forEach(c => { let dis = this.distanceTo(c); - if (dis < c.radius) { - this.approach(c, dis - c.radius); - this.halt(); + + if (dis < c.radius + this.maxRadius) { + this.modules.forEach(m => { + this.checkModuleCollision(m, c); + }); } }) } + checkModuleCollision(module, body) { + let p = this.getWorldPoint(...module.localCom) + let dis = body.distanceTo({ com: p }); + if (dis < body.radius + 0.5) { + this.approach(body, dis - (body.radius + 0.5)); + this.halt(); + } + } + applyThrust({ forward = 0, left = 0, right = 0, back = 0, turnLeft = 0, turnRight = 0}) { let turnForce = (turnRight - turnLeft) / 20; diff --git a/js/world/spawn.mjs b/js/world/spawn.mjs index 92cfa3f..8c0bd82 100644 --- a/js/world/spawn.mjs +++ b/js/world/spawn.mjs @@ -16,13 +16,13 @@ export function player() { export function startPlanet() { return celestial(0, 0, 40, { - density: 1, + density: 10, type: 'green' }); } export function celestial(x, y, radius, params) { - let celestial = new Celestial(x, y, radius, params); + let celestial = new Celestial(x - radius, y - radius, radius, params); world.celestials.add(celestial); return celestial; }