Large Turtle Collider

Massy particles with weird interactions.

Log in to post a comment.

Canvas.setpenopacity(-0.1);

const nObjects = 4;
const massSize = 5;
const spawnArea = 30;
const startAngle = 15+Math.random()*15;
const iters = 10000;
const gravity = 0.08;

const minVel = 0.01;
const maxVel = 0.05;
const lightspeed = 1.5;
const minMass = 0.4;
const maxMass = 1;
const crashMassLoss = 0.7;
const crashVelocityLoss = 0.1;
const turnVelocityLoss = 0.1;

const edge = 100;
const seed = Math.random()*360;

let newTurtles = [];
let turtles = [...Array(nObjects*nObjects)].map((_, i) => {
    const turtle = new Turtle();
    turtle.velocity = minVel + (maxVel-minVel)*Math.random();
    turtle.mass = minMass + (maxMass-minMass)*Math.random();
    turtle.seth(seed+i*startAngle);
    turtle.penup();
    turtle.goto(
        -spawnArea+spawnArea/nObjects+2*spawnArea/nObjects*(i%nObjects),
        -spawnArea+spawnArea/nObjects+2*spawnArea/nObjects*Math.floor(i/nObjects),
    );
    turtle.pendown();
    return turtle;
});

function angleBetween(a, b) {
    return Math.min((360+a-b)%360, (360+b-a)%360);
}

function walk(i) {
    newTurtles = [];
    for (let index = 0; index < turtles.length; index++) {
        const turtle = turtles[index];
        const tx = turtle.x();
        const ty = turtle.y();
        const otherTurtles = turtles.filter((t, oi) => !t.crashed && oi != index);
        for (let oti = 0; oti < otherTurtles.length; oti++) {
            const ot = otherTurtles[oti];
            const th = turtle.h();
            const ox = ot.x();
            const oy = ot.y();
            const oh = ot.h();
            const dx = ox-tx;
            const dy = oy-ty;
            const angle = angleBetween(th, Math.atan2(dx, dy)*180/Math.PI);
            const dist = Math.sqrt(dx*dx+dy*dy);
            const distFactor = 1/(dist*dist);
            if (dist < (turtle.mass*massSize+ot.mass*massSize)/2) {
                turtle.crashed = true;
                ot.crashed = true;
                const nt = turtle.clone();
                const angleDiff = angleBetween(oh, th);
                nt.mass = ot.mass+turtle.mass*crashMassLoss;
                nt.velocity = (ot.velocity*ot.mass/turtle.velocity*turtle.mass)*crashVelocityLoss;
                nt.goto(ox-dx, oy-dy);
                nt.seth((oh+angleDiff*(ot.mass/turtle.mass))%360);
                newTurtles.push(nt);
            }
            else {
                const turnFactor = ((dx>=0 && dy>0) || (dx<0 && dy>=0) ? 1 : -1)*(distFactor*((ot.mass*ot.mass)/(turtle.mass*turtle.mass))*angle*gravity);
                turtle.velocity *= 1 + distFactor * (turtle.mass/ot.mass) * turnVelocityLoss;
                turtle.right(turtle.mass * turnFactor);
            }
        }
        turtle.forward(turtle.velocity - (turtle.velocity/turtle.mass)*(turtle.velocity/lightspeed));
        const size = turtle.mass*massSize;
        turtle.penup();
        turtle.left(90);
        turtle.forward(size/2);
        turtle.right(90);
        turtle.pendown();
        turtle.circle(size, 360, Math.round(10*turtle.mass));
        turtle.penup();
        turtle.left(90);
        turtle.backward(size/2);
        turtle.right(90);
        if (tx > edge+size || tx < -edge-size || ty >= edge+size || ty < -edge-size) turtle.crashed = true;;
    }
    turtles = turtles.concat(newTurtles).filter(turtle => !turtle.crashed);
    return turtles.length > 0 && i < iters;
}