diff --git a/frontend/src/physics/engineSetup.js b/frontend/src/physics/engineSetup.js index dbfb35b..a0e3121 100644 --- a/frontend/src/physics/engineSetup.js +++ b/frontend/src/physics/engineSetup.js @@ -1,31 +1,6 @@ import Matter from 'matter-js' export const setupMatterEngine = (engine) => { - // Quick hack: override the solver so ropes actually get slack/droop when they're close - if (!Matter.Constraint._originalSolve) { - Matter.Constraint._originalSolve = Matter.Constraint.solve; - Matter.Constraint.solve = function(constraint, timeScale) { - if (constraint.isRope) { - let pA = constraint.pointA; - let pB = constraint.pointB; - if (constraint.bodyA) pA = Matter.Vector.add(constraint.bodyA.position, pA); - if (constraint.bodyB) pB = Matter.Vector.add(constraint.bodyB.position, pB); - - if (pA && pB) { - const dist = Matter.Vector.magnitude(Matter.Vector.sub(pA, pB)); - if (dist < (constraint.maxLength || constraint.length) * 0.99) { - constraint.stiffness = 0; // drop stiffness to 0 to let the rope droop - constraint.render.visible = false; // hide the straight line connection, we'll draw our own bezier curve later - } else { - constraint.stiffness = 1; // yank it tight - constraint.render.visible = true; - } - } - } - Matter.Constraint._originalSolve(constraint, timeScale); - }; - } - Matter.Resolver._restingThresh = 0.001 // push resting threshold down so small bounces don't just die instantly // Matter.js loses energy on elastic collisions, this is a workaround to bump speed back up diff --git a/frontend/src/physics/helpers.js b/frontend/src/physics/helpers.js index 8cb6bd6..9a56efa 100644 --- a/frontend/src/physics/helpers.js +++ b/frontend/src/physics/helpers.js @@ -85,7 +85,10 @@ export const applyConstraintRender = (constraint, isSelected = false) => { export const getConstraintWorldPoint = (body, point) => { if (body) { - return Matter.Vector.add(body.position, point || { x: 0, y: 0 }) + if (body.isStatic) { + return Matter.Vector.add(body.position, point || { x: 0, y: 0 }) + } + return Matter.Vector.add(body.position, Matter.Vector.rotate(point || { x: 0, y: 0 }, body.angle)) } return point || { x: 0, y: 0 } diff --git a/frontend/src/physics/renderLoop.js b/frontend/src/physics/renderLoop.js index 5ddfd3c..9323df9 100644 --- a/frontend/src/physics/renderLoop.js +++ b/frontend/src/physics/renderLoop.js @@ -1,4 +1,5 @@ import Matter from 'matter-js' +import { getConstraintWorldPoint } from './helpers' export const setupRenderLoop = (ctx) => { const { @@ -58,6 +59,31 @@ export const setupRenderLoop = (ctx) => { Matter.Vector.rotate(c.pointB, c.bodyB.angle - c.angleB, c.pointB); c.angleB = c.bodyB.angle; } + + // Check if this constraint is a rope and adjust stiffness/length before physics calculations start + if (c.isRope) { + if (c.maxLength === undefined || c.maxLength === null) { + c.maxLength = c.length || 100; + } + + const pA = getConstraintWorldPoint(c.bodyA, c.pointA); + const pB = getConstraintWorldPoint(c.bodyB, c.pointB); + + if (pA && pB) { + const dist = Matter.Vector.magnitude(Matter.Vector.sub(pA, pB)); + if (dist < c.maxLength * 0.99) { + // Let the rope droop without any push/pull force + c.stiffness = 0; + c.length = dist; + c.render.visible = false; + } else { + // Tight constraint: prevent moving beyond maxLength + c.stiffness = 1; + c.length = c.maxLength; + c.render.visible = true; + } + } + } }); // Kill air resistance to keep momentum pure, and tick motorized gears/rods forward @@ -156,8 +182,8 @@ export const setupRenderLoop = (ctx) => { // Draw rope as a curving quadratic bezier path when it gets slack engine.world.constraints.forEach(c => { if (c.isRope && c.stiffness === 0) { - const pA = c.bodyA ? Matter.Vector.add(c.bodyA.position, c.pointA) : c.pointA; - const pB = c.bodyB ? Matter.Vector.add(c.bodyB.position, c.pointB) : c.pointB; + const pA = getConstraintWorldPoint(c.bodyA, c.pointA); + const pB = getConstraintWorldPoint(c.bodyB, c.pointB); context.beginPath(); context.moveTo(pA.x, pA.y);