Skip to content

Commit

Permalink
fix: composite multi contact (#3351)
Browse files Browse the repository at this point in the history
This PR fixes and issue where composite colliders in the "together" strategy contacts were being resolved multiple times in the ArcadeSolver causing visual jitter/artifacts
  • Loading branch information
eonarheim authored Jan 31, 2025
1 parent aaafeac commit 907972d
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/engine/Collision/Colliders/Shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export class Shape {
Shape.Box(width, height - width, Vector.Half, offset),
Shape.Circle(width / 2, vec(0, height / 2 - width / 2).add(offset))
]);
capsule.compositeStrategy = 'together';
return capsule;
} else {
// width > height, if equal maybe use a circle
Expand All @@ -99,6 +100,7 @@ export class Shape {
Shape.Box(width - height, height, Vector.Half, offset),
Shape.Circle(height / 2, vec(width / 2 - height / 2, 0).add(offset))
]);
capsule.compositeStrategy = 'together';
return capsule;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/engine/Collision/CollisionSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class CollisionSystem extends System {
this._currentFrameContacts.clear();

// Given possible pairs find actual contacts
let contacts: CollisionContact[] = []; // = this._processor.narrowphase(pairs, this._engine?.debug?.stats?.currFrame);
let contacts: CollisionContact[] = [];

const solver: CollisionSolver = this.getSolver();

Expand Down
2 changes: 1 addition & 1 deletion src/engine/Collision/Detection/CollisionContact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class CollisionContact {
this.info = info;
this.id = Pair.calculatePairHash(colliderA.id, colliderB.id);
if (colliderA.composite || colliderB.composite) {
// Add on the parent composite pair for start/end contact if 'together
// Add on the parent composite pair for start/end contact if 'together'
const colliderAId = colliderA.composite?.compositeStrategy === 'separate' ? colliderA.id : colliderA.composite?.id ?? colliderA.id;
const colliderBId = colliderB.composite?.compositeStrategy === 'separate' ? colliderB.id : colliderB.composite?.id ?? colliderB.id;
this.id += '|' + Pair.calculatePairHash(colliderAId, colliderBId);
Expand Down
18 changes: 17 additions & 1 deletion src/engine/Collision/Solver/ArcadeSolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,30 @@ export class ArcadeSolver implements CollisionSolver {
return contacts;
}

private _compositeContactsIds = new Set<string>();
public preSolve(contacts: CollisionContact[]) {
const epsilon = 0.0001;
for (let i = 0; i < contacts.length; i++) {
const contact = contacts[i];

// Cancel dup composite together strategy contacts
const index = contact.id.indexOf('|');
if (index > 0) {
const compositeId = contact.id.substring(index + 1);
if (this._compositeContactsIds.has(compositeId)) {
contact.cancel();
continue;
}
this._compositeContactsIds.add(compositeId);
}

// Cancel near 0 mtv collisions
if (Math.abs(contact.mtv.x) < epsilon && Math.abs(contact.mtv.y) < epsilon) {
// Cancel near 0 mtv collisions
contact.cancel();
continue;
}

// Record distance/direction for sorting
const side = Side.fromDirection(contact.mtv);
const mtv = contact.mtv.negate();

Expand All @@ -93,6 +108,7 @@ export class ArcadeSolver implements CollisionSolver {
new PreCollisionEvent(contact.colliderB, contact.colliderA, Side.getOpposite(side), mtv.negate(), contact)
);
}
this._compositeContactsIds.clear();
}

public postSolve(contacts: CollisionContact[]) {
Expand Down

0 comments on commit 907972d

Please sign in to comment.