Fix collider tunneling, seed the container demo, split the e2e fixture
Move with "Collide with solids" now steps in sub-steps of at most half the thinnest collider, so a fast step can no longer jump across a collider (the crates are only 60 high, which is why it showed up mostly on the y axis). A pre-existing overlap is still never resolved, but it can no longer be deepened either, so a small overlap cannot open a wall permanently. seed-demo.mjs now writes the saved demo scene: a "Player" container (green sprite with collider and the Mover behavior) against two "Enemy" container instances, camera at zoom 0.5, Spawner dropping another enemy on Space. The e2e checks assert against the old two-crate layout and locate widgets by text, which the demo can no longer provide (three identically named sprite instances, both crates nested in containers). Its fixture therefore moves to tools/seed-e2e.mjs so the shipped demo can evolve without rewriting 100+ checks: seed-e2e -> e2e -> seed-demo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3379232e64
commit
4900d7bbf6
6 files changed
+269
-39
No files matched your search
@@ -150,6 +150,8 @@ describe('CollisionSystem', () => {
|
||||
});
|
||||
|
||||
describe('move and slide', () => {
|
||||
const SKIN = 0.05; // mirrors CollisionSystem: overlaps this shallow count as contact
|
||||
|
||||
function runtime() {
|
||||
const s = setup();
|
||||
const world = World.instantiate(s.project, s.sceneId);
|
||||
@@ -197,13 +199,33 @@ describe('move and slide', () => {
|
||||
expect(crateA.x).toBe(260);
|
||||
});
|
||||
|
||||
it('pairs that already overlap are not resolved (no jolt), leaving is always possible', () => {
|
||||
it('an existing overlap is neither resolved (no jolt) nor deepened; leaving is always possible', () => {
|
||||
const { world, collisions, crateA, crateB } = runtime();
|
||||
crateB.x = 60; // start overlapped
|
||||
expect(collisions.moveAndSlide(world, crateA, 5, 0)).toEqual({ blockedX: false, blockedY: false });
|
||||
expect(crateA.x).toBe(5);
|
||||
crateB.x = 60; // start overlapped by 40
|
||||
expect(collisions.moveAndSlide(world, crateA, 5, 0)).toEqual({ blockedX: true, blockedY: false });
|
||||
expect(crateA.x).toBe(0); // no jolt out, but no burrowing deeper either
|
||||
expect(collisions.moveAndSlide(world, crateA, -20, 0)).toEqual({ blockedX: false, blockedY: false });
|
||||
expect(crateA.x).toBe(-20); // moving away is always free
|
||||
expect(collisions.moveAndSlide(world, crateA, -100, 0)).toEqual({ blockedX: false, blockedY: false });
|
||||
expect(crateA.x).toBe(-95);
|
||||
expect(crateA.x).toBe(-120);
|
||||
});
|
||||
|
||||
it('keeps blocking while pressed against a wall, however long and at any speed', () => {
|
||||
const { world, collisions, crateA, crateB } = runtime();
|
||||
crateB.x = 0;
|
||||
crateB.y = 300; // wall straight above, colliders are 100×60 → contact at y = 240
|
||||
for (let i = 0; i < 500; i++) {
|
||||
// Uneven steps, so contact is never hit at a round number.
|
||||
const { blockedY } = collisions.moveAndSlide(world, crateA, 0, 3.7 + (i % 7) * 0.13);
|
||||
expect(crateA.y).toBeLessThanOrEqual(240 + SKIN);
|
||||
if (i > 60) expect(blockedY).toBe(true);
|
||||
}
|
||||
expect(crateA.y).toBeGreaterThan(240 - SKIN);
|
||||
// A step larger than the obstacle used to jump clean over it: after the move nothing
|
||||
// overlapped any more, so nothing pushed back and the mover was through the wall.
|
||||
crateA.y = 0;
|
||||
expect(collisions.moveAndSlide(world, crateA, 0, 5000)).toEqual({ blockedX: false, blockedY: true });
|
||||
expect(crateA.y).toBeCloseTo(240, 6);
|
||||
});
|
||||
|
||||
it('the Move node with "Collide with solids" moves the owner and outputs the blocked axes', () => {
|
||||
|
||||
Reference in new issue
Block a user