import {GRAVITATIONAL_CONSTANT as G, TAU} from '../consts.mjs'; export default class Body { constructor(x, y, mass) { this.x = x; this.y = y; this.r = 0; this.xvel = 0; this.yvel = 0; this.rvel = 0; this.rfriction = 0.9; this.mass = mass; } get com() { return [this.x, this.y]; } get pos() { return [this.x, this.y]; } get speed() { 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 => { let dis = this.distanceTo(c); if (dis < c.radius) result = c; }); return result; } getWorldPoint(lx, ly, test) { 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 = this.r) { return [(x * Math.cos(-r) + y * Math.sin(-r)), -(-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); } tickMotion(speed = 1) { this.x += this.xvel * speed; this.y += this.yvel * speed; this.r += this.rvel * speed; this.rvel *= this.rfriction * speed; } tickGravity(bodies, speed = 1) { bodies.forEach(b => { let force = b.mass / (this.distanceTo(b) ** 2) * G; let [[ax, ay], [bx, by]] = [this.com, b.com]; let angle = Math.atan2(by - ay, bx - ax); this.xvel += Math.cos(angle) * force * speed; this.yvel += Math.sin(angle) * force * speed; }); } distanceTo(body) { let [[ax, ay], [bx, by]] = [this.com, body.com]; return Math.max(Math.sqrt(((bx - ax) ** 2) + ((by - ay) ** 2)), 1); } angleTo(ax, ay, bx, by) { return Math.atan2(by - ay, bx - ax); } approach(body, distance) { 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; } halt() { this.xvel = 0; this.yvel = 0; } applyDirectionalForce(x, y, r) { let [vx, vy] = this.rotateVector(x, y); this.xvel += vx / this.mass; this.yvel += vy / this.mass; this.rvel += r / this.mass; } orbit(cel, altitude, angle = 0) { this.gravity = true; let speed = Math.sqrt(G * cel.mass / (altitude + cel.radius)); let [cx, cy] = cel.com; let [comX, comY] = this.localCom; let [dx, dy] = this.rotateVector(0, -(altitude + cel.radius), angle); [this.xvel, this.yvel] = this.rotateVector(speed, 0, angle); this.x = cx + dx - comX; this.y = cy + dy - comY; } }