From 16c3f22334cd4fbc022f3ea6a0bc1ea74e990b6c Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Sat, 30 May 2026 17:36:39 -0500 Subject: [PATCH] fix: accidental shadowing in solver, could be foot gun --- .../collision/solver/realistic-solver.ts | 8 +++--- src/spec/vitest/realistic-solver-spec.ts | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/engine/collision/solver/realistic-solver.ts b/src/engine/collision/solver/realistic-solver.ts index 1df0ca5839..abb3496f85 100644 --- a/src/engine/collision/solver/realistic-solver.ts +++ b/src/engine/collision/solver/realistic-solver.ts @@ -280,8 +280,8 @@ export class RealisticSolver implements CollisionSolver { */ solvePosition(contacts: CollisionContact[]) { for (let i = 0; i < this.config.positionIterations; i++) { - for (let i = 0; i < contacts.length; i++) { - const contact = contacts[i]; + for (let j = 0; j < contacts.length; j++) { + const contact = contacts[j]; const bodyA = contact.bodyA; const bodyB = contact.bodyB; @@ -350,8 +350,8 @@ export class RealisticSolver implements CollisionSolver { solveVelocity(contacts: CollisionContact[]) { // velocityIterations: for (let i = 0; i < this.config.velocityIterations; i++) { - for (let i = 0; i < contacts.length; i++) { - const contact = contacts[i]; + for (let j = 0; j < contacts.length; j++) { + const contact = contacts[j]; const bodyA = contact.bodyA; const bodyB = contact.bodyB; diff --git a/src/spec/vitest/realistic-solver-spec.ts b/src/spec/vitest/realistic-solver-spec.ts index ff3fc18026..a2cff34df9 100644 --- a/src/spec/vitest/realistic-solver-spec.ts +++ b/src/spec/vitest/realistic-solver-spec.ts @@ -44,4 +44,30 @@ describe('A RealisticSolver', () => { // Considers infinitesimally overlapping to no longer be overlapping and thus cancels the contact expect(contact.isCanceled()).toBe(true); }); + + it('should run the configured number of position and velocity iterations without variable shadowing issues', () => { + const config = { ...getDefaultPhysicsConfig().realistic, positionIterations: 3, velocityIterations: 4 }; + const realisticSolver = new ex.RealisticSolver(config); + + const actor1 = new ex.Actor({ x: 0, y: 0, width: 40, height: 40, collisionType: ex.CollisionType.Active }); + const actor2 = new ex.Actor({ x: 30, y: 0, width: 40, height: 40, collisionType: ex.CollisionType.Active }); + + const contact = new ex.CollisionContact( + actor1.collider.get(), + actor2.collider.get(), + ex.Vector.Right, + ex.Vector.Right, + ex.Vector.Up, + [ex.vec(20, 0)], + [ex.vec(20, 0)], + null + ); + contact.mtv = ex.vec(10, 0); + + // Should not throw and should complete successfully with multiple iterations + realisticSolver.preSolve([contact]); + realisticSolver.solvePosition([contact]); + realisticSolver.solveVelocity([contact]); + realisticSolver.postSolve([contact]); + }); });