Skip to content

Commit

Permalink
fix: rayCast filter called in hit order
Browse files Browse the repository at this point in the history
  • Loading branch information
eonarheim committed Jul 25, 2024
1 parent 9f28925 commit b3fdd9d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ are doing mtv adjustments during precollision.

### Fixed

- Fixed issue where rayCast `filter` would not be called in hit order
- Fixed issue where rayCasts would return inconsistent orderings with the `ex.SparseHashGridCollisionProcessor` strategy
- Fixed issue where CircleCollider tangent raycast did not work correctly
- Fixed issue where you were required to provide a transition if you provided a loader in the `ex.Engine.start('scene', { loader })`
Expand Down
4 changes: 3 additions & 1 deletion src/engine/Collision/Detection/RayCastOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export interface RayCastOptions {
*/
collisionMask?: number;
/**
* Optionally specify to search for all colliders that intersect the ray cast, not just the first which is the default
* Optionally search for all colliders that intersect the ray cast.
*
* Default false
*/
searchAllColliders?: boolean;
/**
Expand Down
34 changes: 22 additions & 12 deletions src/engine/Collision/Detection/SparseHashGridCollisionProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export class SparseHashGridCollisionProcessor implements CollisionProcessor {
const key = HashGridCell.calculateHashKey(currentXCoord, currentYCoord);
const cell = this.hashGrid.sparseHashGrid.get(key);
if (cell) {
const cellHits: RayCastHit[] = [];
for (let colliderIndex = 0; colliderIndex < cell.proxies.length; colliderIndex++) {
const collider = cell.proxies[colliderIndex];
if (!collidersVisited.has(collider.collider.id.value)) {
Expand All @@ -197,21 +198,30 @@ export class SparseHashGridCollisionProcessor implements CollisionProcessor {

const hit = collider.collider.rayCast(ray, maxDistance);

// Collect up all the colliders that hit inside a cell
// they can be in any order so we need to sort them next
if (hit) {
if (options?.filter) {
if (options.filter(hit)) {
results.push(hit);
if (!searchAllColliders) {
done = true;
}
}
} else {
results.push(hit);
if (!searchAllColliders) {
done = true;
}
cellHits.push(hit);
}
}
}
cellHits.sort((hit1, hit2) => hit1.distance - hit2.distance);
for (let i = 0; i < cellHits.length; i++) {
const hit = cellHits[i];
if (options?.filter) {
if (options.filter(hit)) {
results.push(hit);
if (!searchAllColliders) {
done = true;
break;
}
}
} else {
results.push(hit);
if (!searchAllColliders) {
done = true;
break;
}
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/spec/SparseHashGridCollisionProcessorSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,4 +340,31 @@ describe('A Sparse Hash Grid Broadphase', () => {
expect(hits[1].distance).toBe(175);
expect(hits[1].point).toEqual(ex.vec(175, 0));
});

it('calls filter in hit order', () => {
const sut = new ex.SparseHashGridCollisionProcessor({ size: 200 });
const actor3 = new ex.Actor({ x: 104, y: 0, width: 50, height: 50 });
sut.track(actor3.collider.get());
const actor2 = new ex.Actor({ x: 102, y: 0, radius: 25 });
sut.track(actor2.collider.get());
const actor1 = new ex.Actor({ x: 100, y: 0, radius: 25 });
sut.track(actor1.collider.get());

const ray = new ex.Ray(ex.vec(0, 0), ex.Vector.Right);
const filter = jasmine.createSpy('filter').and.callFake(() => true);
const hits = sut.rayCast(ray, {
searchAllColliders: true,
filter
});

expect(filter.calls.argsFor(0)).toEqual([
{ point: ex.vec(75, 0), distance: 75, collider: actor1.collider.get(), body: actor1.body, normal: ex.vec(-1, 0) }
]);
expect(filter.calls.argsFor(1)).toEqual([
{ point: ex.vec(77, 0), distance: 77, collider: actor2.collider.get(), body: actor2.body, normal: ex.vec(-1, 0) }
]);
expect(filter.calls.argsFor(2)).toEqual([
{ point: ex.vec(79, 0), distance: 79, collider: actor3.collider.get(), body: actor3.body, normal: ex.vec(-1, -0) }
]);
});
});

0 comments on commit b3fdd9d

Please sign in to comment.