Skip to content

Commit

Permalink
fix: rayCast returns consistent ordering of hit distance
Browse files Browse the repository at this point in the history
  • Loading branch information
eonarheim committed Jul 24, 2024
1 parent 2f4360d commit 9f28925
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 2 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 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 })`
- Fixed issue where `ex.Scene.onPreLoad(loader: ex.DefaultLoader)` would lock up the engine if there was an empty loader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,12 @@ export class SparseHashGridCollisionProcessor implements CollisionProcessor {
results.push(hit);
if (!searchAllColliders) {
done = true;
break;
}
}
} else {
results.push(hit);
if (!searchAllColliders) {
done = true;
break;
}
}
}
Expand All @@ -227,6 +225,11 @@ export class SparseHashGridCollisionProcessor implements CollisionProcessor {
}
}

// Sort by distance
results.sort((hit1, hit2) => hit1.distance - hit2.distance);
if (!searchAllColliders && results.length) {
return [results[0]];
}
return results;
}

Expand Down
79 changes: 79 additions & 0 deletions src/spec/SparseHashGridCollisionProcessorSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,83 @@ describe('A Sparse Hash Grid Broadphase', () => {
expect(hits[0].distance).toBe(275);
expect(hits[0].point).toEqual(ex.vec(275, 0));
});

it('can rayCast and have the right first collider returned regardless of track order', () => {
const sut = new ex.SparseHashGridCollisionProcessor({ size: 200 });
const actor3 = new ex.Actor({ x: 300, y: 0, width: 50, height: 50 });
sut.track(actor3.collider.get());
const actor2 = new ex.Actor({ x: 200, y: 0, width: 50, height: 50 });
sut.track(actor2.collider.get());
const actor1 = new ex.Actor({ x: 100, y: 0, width: 50, height: 50 });
sut.track(actor1.collider.get());

const ray = new ex.Ray(ex.vec(0, 0), ex.Vector.Right);
const hits = sut.rayCast(ray, {
searchAllColliders: false
});

expect(hits.length).toBe(1);
expect(hits[0].body).toEqual(actor1.body);
expect(hits[0].collider).toEqual(actor1.collider.get());
expect(hits[0].distance).toBe(75);
expect(hits[0].point).toEqual(ex.vec(75, 0));
});

it('can rayCast and have the right ordering returned regardless of track order', () => {
const sut = new ex.SparseHashGridCollisionProcessor({ size: 200 });
const actor3 = new ex.Actor({ x: 300, y: 0, width: 50, height: 50 });
sut.track(actor3.collider.get());
const actor2 = new ex.Actor({ x: 200, y: 0, width: 50, height: 50 });
sut.track(actor2.collider.get());
const actor1 = new ex.Actor({ x: 100, y: 0, width: 50, height: 50 });
sut.track(actor1.collider.get());

const ray = new ex.Ray(ex.vec(0, 0), ex.Vector.Right);
const hits = sut.rayCast(ray, {
searchAllColliders: true
});

expect(hits.length).toBe(3);
expect(hits[0].body).toEqual(actor1.body);
expect(hits[0].collider).toEqual(actor1.collider.get());
expect(hits[0].distance).toBe(75);
expect(hits[0].point).toEqual(ex.vec(75, 0));

expect(hits[1].body).toEqual(actor2.body);
expect(hits[1].collider).toEqual(actor2.collider.get());
expect(hits[1].distance).toBe(175);
expect(hits[1].point).toEqual(ex.vec(175, 0));

expect(hits[2].body).toEqual(actor3.body);
expect(hits[2].collider).toEqual(actor3.collider.get());
expect(hits[2].distance).toBe(275);
expect(hits[2].point).toEqual(ex.vec(275, 0));
});

it('can rayCast to max distance and have the right ordering returned regardless of track order', () => {
const sut = new ex.SparseHashGridCollisionProcessor({ size: 200 });
const actor3 = new ex.Actor({ x: 300, y: 0, width: 50, height: 50 });
sut.track(actor3.collider.get());
const actor2 = new ex.Actor({ x: 200, 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 hits = sut.rayCast(ray, {
searchAllColliders: true,
maxDistance: 175
});

expect(hits.length).toBe(2);
expect(hits[0].body).toEqual(actor1.body);
expect(hits[0].collider).toEqual(actor1.collider.get());
expect(hits[0].distance).toBe(75);
expect(hits[0].point).toEqual(ex.vec(75, 0));

expect(hits[1].body).toEqual(actor2.body);
expect(hits[1].collider).toEqual(actor2.collider.get());
expect(hits[1].distance).toBe(175);
expect(hits[1].point).toEqual(ex.vec(175, 0));
});
});

0 comments on commit 9f28925

Please sign in to comment.