UNPKG

pocket-physics

Version:

Verlet physics extracted from pocket-ces demos

185 lines (184 loc) 7.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.collideCircleEdge = void 0; const v2_1 = require("./v2"); const collide_circle_circle_1 = require("./collide-circle-circle"); // Preallocations const edgeDir = (0, v2_1.v2)(); const edge = (0, v2_1.v2)(); const prevEdge = (0, v2_1.v2)(); const hypo = (0, v2_1.v2)(); const epDiff = (0, v2_1.v2)(); const correction = (0, v2_1.v2)(); const collisionPoint = (0, v2_1.v2)(); const tunnelPoint = (0, v2_1.v2)(); const ep = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; const epBefore = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; function collideCircleEdge(circle, radius3, mass3, endpoint1, mass1, endpoint2, mass2, preserveInertia, damping) { // Edge direction (edge in local space) (0, v2_1.sub)(edge, endpoint2.cpos, endpoint1.cpos); // Normalize collision edge (assume collision axis is edge) (0, v2_1.normalize)(edgeDir, edge); // Vector from endpoint1 to particle (0, v2_1.sub)(hypo, circle.cpos, endpoint1.cpos); // Where is the particle on the edge, before, after, or on? // Also used for interpolation later. const projection = (0, v2_1.dot)(edge, hypo); const maxDot = (0, v2_1.dot)(edge, edge); const edgeMag = Math.sqrt(maxDot); // Colliding beyond the edge... if (projection < 0 || projection > maxDot) return; // Create interpolation factor of where point closest // to particle is on the line. const t = projection / maxDot; const u = 1 - t; // Find the point of collision on the edge. (0, v2_1.scale)(collisionPoint, edgeDir, t * edgeMag); (0, v2_1.add)(collisionPoint, collisionPoint, endpoint1.cpos); const dist = (0, v2_1.distance)(collisionPoint, circle.cpos); // Bail if point and edge are too far apart. if (dist > radius3) return; // Distribute mass of colliding point into two fake points // and use those to collide against each endpoint independently. const standinMass1 = u * mass3; const standinMass2 = t * mass3; const standin1 = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; const standin2 = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; // Slide standin1 along edge to be in front of endpoint1 (0, v2_1.scale)(standin1.cpos, edgeDir, t * edgeMag); (0, v2_1.sub)(standin1.cpos, circle.cpos, standin1.cpos); (0, v2_1.scale)(standin1.ppos, edgeDir, t * edgeMag); (0, v2_1.sub)(standin1.ppos, circle.ppos, standin1.ppos); // Slide standin2 along edge to be in front of endpoint2 (0, v2_1.scale)(standin2.cpos, edgeDir, u * edgeMag); (0, v2_1.add)(standin2.cpos, circle.cpos, standin2.cpos); (0, v2_1.scale)(standin2.ppos, edgeDir, u * edgeMag); (0, v2_1.add)(standin2.ppos, circle.ppos, standin2.ppos); const standin1Before = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; const standin2Before = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; // Stash state of standins (0, v2_1.copy)(standin1Before.cpos, standin1.cpos); (0, v2_1.copy)(standin1Before.ppos, standin1.ppos); (0, v2_1.copy)(standin2Before.cpos, standin2.cpos); (0, v2_1.copy)(standin2Before.ppos, standin2.ppos); const edgeRadius = 0; // Collide standins with endpoints (0, collide_circle_circle_1.collideCircleCircle)(standin1, radius3, standinMass1, endpoint1, edgeRadius, mass1, preserveInertia, damping); (0, collide_circle_circle_1.collideCircleCircle)(standin2, radius3, standinMass2, endpoint2, edgeRadius, mass2, preserveInertia, damping); const standin1Delta = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; const standin2Delta = { cpos: (0, v2_1.v2)(), ppos: (0, v2_1.v2)() }; // Compute standin1 cpos change (0, v2_1.sub)(standin1Delta.cpos, standin1.cpos, standin1Before.cpos); // Compute standin2 cpos change (0, v2_1.sub)(standin2Delta.cpos, standin2.cpos, standin2Before.cpos); (0, v2_1.scale)(standin1Delta.cpos, standin1Delta.cpos, u); (0, v2_1.scale)(standin2Delta.cpos, standin2Delta.cpos, t); // Apply cpos changes to point3 (0, v2_1.add)(circle.cpos, circle.cpos, standin1Delta.cpos); (0, v2_1.add)(circle.cpos, circle.cpos, standin2Delta.cpos); if (!preserveInertia) return; // TODO: instead of adding diff, get magnitude of diff and scale // in reverse direction of standin velocity from point3.cpos because // that is what circlecircle does. // Compute standin1 ppos change (0, v2_1.sub)(standin1Delta.ppos, standin1.ppos, standin1Before.ppos); // Compute standin2 ppos change (0, v2_1.sub)(standin2Delta.ppos, standin2.ppos, standin2Before.ppos); (0, v2_1.scale)(standin1Delta.ppos, standin1Delta.ppos, u); (0, v2_1.scale)(standin2Delta.ppos, standin2Delta.ppos, t); // Apply ppos changes to point3 (0, v2_1.add)(circle.ppos, circle.ppos, standin1Delta.ppos); (0, v2_1.add)(circle.ppos, circle.ppos, standin2Delta.ppos); } exports.collideCircleEdge = collideCircleEdge; function snapshotDebug(name, particles = [], points = []) { const cvs = document.createElement("canvas"); const ctx = cvs.getContext("2d"); document.body.appendChild(cvs); // let minX = Number.MAX_SAFE_INTEGER; // let maxX = Number.MIN_SAFE_INTEGER; // let minY = Number.MAX_SAFE_INTEGER; // let maxY = Number.MIN_SAFE_INTEGER; // for (let i = 0; i < particles.length; i++) { // const particle = particles[i]; // minX = Math.min( // minX, // particle.cpos.x - particle.radius, // particle.ppos.x - particle.radius // ); // maxX = Math.max( // maxX, // particle.cpos.x + particle.radius, // particle.ppos.x + particle.radius // ); // minY = Math.min( // minY, // particle.cpos.y - particle.radius, // particle.ppos.y - particle.radius // ); // maxY = Math.max( // maxY, // particle.cpos.y + particle.radius, // particle.ppos.y + particle.radius // ); // } // for (let i = 0; i < points.length; i++) { // const [, point] = points[i]; // minX = Math.min(minX, point.x, point.x); // maxX = Math.max(maxX, point.x, point.x); // minY = Math.min(minY, point.y, point.y); // maxY = Math.max(maxY, point.y, point.y); // } // cvs.width = maxX - minX; // cvs.height = maxY - minY; // ctx.translate(-minX, -minY); cvs.width = 800; cvs.height = 800; for (let i = 0; i < particles.length; i++) { const particle = particles[i]; ctx.fillStyle = "rgba(255, 0, 0, 0.5)"; ctx.beginPath(); ctx.arc(particle.ppos.x, particle.ppos.y, particle.radius, 0, Math.PI * 2, false); ctx.fill(); ctx.fillStyle = "rgba(0, 0, 0, 0.5)"; ctx.beginPath(); ctx.arc(particle.cpos.x, particle.cpos.y, particle.radius, 0, Math.PI * 2, false); ctx.fill(); } for (let i = 0; i < points.length; i++) { const [name, point] = points[i]; ctx.fillStyle = "purple"; ctx.fillRect(point.x, point.y, 1, 1); ctx.fillText(`${name} (${point.x},${point.y})`, point.x + 1, point.y + 1); } // ctx.translate(minX, minY); ctx.fillStyle = "black"; ctx.fillText(name, 10, 10); }