draw = (context) => {
const { objects, G } = context;
const stats = (context.stats = context.stats || {});
for (let step = 1; step <= mutable speed.value; ++step) {
objects.forEach((a) => {
objects.forEach((b) => {
if (a === b) return;
let d = Math.abs(FastVector.distance(a.pos, b.pos));
if (d < a.r + b.r) d = (a.r + b.r) / 1.1;
let r2 = Math.pow(d, 2);
let f = (G * a.m * b.m) / r2;
let fa = b.pos.sub(a.pos).normalize().mul(f);
let fb = a.pos.sub(b.pos).normalize().mul(f);
a.acc = a.acc.add(fa.div(a.m));
b.acc = b.acc.add(fb.div(b.m));
});
});
objects.forEach((obj) => {
obj.vel = obj.vel.add(obj.acc);
obj.pos = obj.pos.add(obj.vel);
obj.acc.x = 0;
obj.acc.y = 0;
if (!stats.min) stats.min = obj.pos.clone();
if (stats.min.x > obj.pos.x) stats.min.x = obj.pos.x;
if (stats.min.y > obj.pos.y) stats.min.y = obj.pos.y;
if (!stats.max) stats.max = obj.pos.clone();
if (stats.max.x < obj.pos.x) stats.max.x = obj.pos.x;
if (stats.max.y < obj.pos.y) stats.max.y = obj.pos.y;
if (!stats.r) stats.r = { min: obj.r, max: obj.r };
if (obj.r < stats.r.min) stats.r.min = obj.r;
if (obj.r > stats.r.max) stats.r.max = obj.r;
});
}
stats.dist = FastVector.distance(stats.max, stats.min);
let zoom = Math.sqrt(width * width + height * height) / stats.dist;
p8g.colorMode(p8g.HSB);
p8g.background(0, 0, 0);
p8g.fill(0, 0, 100);
const minXY = Math.min(stats.min.x, stats.min.y);
const maxXY = Math.max(stats.max.x, stats.max.y);
objects.forEach((obj) => {
let x = map(obj.pos.x, minXY, maxXY, 0, width);
let y = map(obj.pos.y, minXY, maxXY, 0, height);
let r = zoom * obj.r;
p8g.ellipse(x, y, r, r);
});
}