pocket-physics
Version:
Verlet physics extracted from pocket-ces demos
78 lines (61 loc) • 2.47 kB
text/typescript
import { add, distance2, set, sub } from "./v2";
import { VelocityDerivable } from "./common-types";
// Preallocations!
const vel1 = { x: 0, y: 0 };
const vel2 = { x: 0, y: 0 };
const diff = { x: 0, y: 0 };
const move = { x: 0, y: 0 };
// TODO: is the below even true???
// The codeflow demo does nothing if the circles are no longer overlapping.
// It's very important that this function not do any distance checking.
// It is assumed that if this function is called, then the points are
// definitely colliding, and that after being called with preserveInertia
// === false, another call with === true should be made, even if the first
// calculation has moved the points away from physically touching.
export const collideCircleCircle = (
p1: VelocityDerivable,
p1radius: number,
p1mass: number,
p2: VelocityDerivable,
p2radius: number,
p2mass: number,
preserveInertia: boolean,
damping: number
) => {
const dist2 = distance2(p1.cpos, p2.cpos);
const target = p1radius + p2radius;
const min2 = target * target;
// if (dist2 > min2) return;
sub(vel1, p1.cpos, p1.ppos);
sub(vel2, p2.cpos, p2.ppos);
sub(diff, p1.cpos, p2.cpos);
const dist = Math.sqrt(dist2);
let factor = (dist - target) / dist;
// Avoid division by zero in case points are directly atop each other.
if (dist === 0) factor = 1;
const mass1 = p1mass > 0 ? p1mass : 1;
const mass2 = p2mass > 0 ? p2mass : 1;
const massT = mass1 + mass2;
// Move a away
move.x = diff.x * factor * (mass2 / massT);
move.y = diff.y * factor * (mass2 / massT);
if (p1mass > 0) {
sub(p1.cpos, p1.cpos, move);
}
// Move b away
move.x = diff.x * factor * (mass1 / massT);
move.y = diff.y * factor * (mass1 / massT);
if (p2mass > 0) {
add(p2.cpos, p2.cpos, move);
}
if (!preserveInertia) return;
damping = damping || 1;
const f1 = (damping * (diff.x * vel1.x + diff.y * vel1.y)) / (dist2 || 1);
const f2 = (damping * (diff.x * vel2.x + diff.y * vel2.y)) / (dist2 || 1);
vel1.x += (f2 * diff.x - f1 * diff.x) / (mass1 || 1); // * (mass2 / massT);
vel2.x += (f1 * diff.x - f2 * diff.x) / (mass2 || 1); // * (mass1 / massT);
vel1.y += (f2 * diff.y - f1 * diff.y) / (mass1 || 1); // * (mass2 / massT);
vel2.y += (f1 * diff.y - f2 * diff.y) / (mass2 || 1); // * (mass1 / massT);
if (p1mass > 0) set(p1.ppos, p1.cpos.x - vel1.x, p1.cpos.y - vel1.y);
if (p2mass > 0) set(p2.ppos, p2.cpos.x - vel2.x, p2.cpos.y - vel2.y);
};