Skip to content

Commit

Permalink
feat: add CollisionContact.bias(collider) (#3122)
Browse files Browse the repository at this point in the history
Follow up from #3121

## Changes:

- CollisionContact can be biased toward a collider by using `contact.bias(collider)`. This adjusts the contact so that the given collider is colliderA, and is helpful if you 
are doing mtv adjustments during precollision.

---------

Co-authored-by: Erik Onarheim <erik.onarheim@gmail.com>
  • Loading branch information
mattjennings and eonarheim authored Jul 8, 2024
1 parent 7a4c821 commit e57fd3f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- show warning in development when Entity hasn't been added to a scene after a few seconds
- New `RentalPool` type for sparse object pooling
- New `ex.SparseHashGridCollisionProcessor` which is a simpler (and faster) implementation for broadphase pair generation. This works by bucketing colliders into uniform sized square buckets and using that to generate pairs.
- CollisionContact can be biased toward a collider by using `contact.bias(collider)`. This adjusts the contact so that the given collider is colliderA, and is helpful if you
are doing mtv adjustments during precollision.

### Fixed

Expand Down
24 changes: 24 additions & 0 deletions src/engine/Collision/Detection/CollisionContact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,28 @@ export class CollisionContact {
public cancel(): void {
this._canceled = true;
}

/**
* Biases the contact so that the given collider is colliderA
*/
public bias(collider: Collider) {
if (collider !== this.colliderA && collider !== this.colliderB) {
throw new Error('Collider must be either colliderA or colliderB from this contact');
}

if (collider === this.colliderA) {
return this;
}

const colliderA = this.colliderA;
const colliderB = this.colliderB;

this.colliderB = colliderA;
this.colliderA = colliderB;
this.mtv = this.mtv.negate();
this.normal = this.normal.negate();
this.tangent = this.tangent.negate();

return this;
}
}
23 changes: 23 additions & 0 deletions src/spec/CollisionContactSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TransformComponent } from '@excalibur';
import { EulerIntegrator } from '../engine/Collision/Integrator';
import { MotionComponent } from '../engine/EntityComponentSystem/Components/MotionComponent';
import { DefaultPhysicsConfig } from '../engine/Collision/PhysicsConfig';
import { ExcaliburMatchers } from 'excalibur-jasmine';

describe('A CollisionContact', () => {
let actorA: ex.Actor;
Expand All @@ -12,6 +13,7 @@ describe('A CollisionContact', () => {
let colliderB: ex.Collider;

beforeEach(() => {
jasmine.addMatchers(ExcaliburMatchers);
actorA = new ex.Actor({ x: 0, y: 0, width: 20, height: 20 });
actorA.collider.useCircleCollider(10);
actorA.body.collisionType = ex.CollisionType.Active;
Expand Down Expand Up @@ -326,4 +328,25 @@ describe('A CollisionContact', () => {
expect(emittedA).toBe(true);
expect(emittedB).toBe(true);
});

it('biases to colliderB', () => {
const cc = new ex.CollisionContact(
colliderA,
colliderB,
ex.Vector.Right,
ex.Vector.Right,
ex.Vector.Right.perpendicular(),
[new ex.Vector(10, 0)],
[new ex.Vector(10, 0)],
null
);

cc.bias(colliderB);

expect(cc.colliderA).toBe(colliderB);
expect(cc.colliderB).toBe(colliderA);
expect(cc.mtv).toBeVector(ex.Vector.Left);
expect(cc.normal).toBeVector(ex.Vector.Left);
expect(cc.tangent).toBeVector(ex.Vector.Left.perpendicular());
});
});

0 comments on commit e57fd3f

Please sign in to comment.