Skip to content

Commit 65160cd

Browse files
committed
fix: take collision into consideration for floor snapping after horizontal dash
1 parent 4972615 commit 65160cd

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/player/Player.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,8 +1369,7 @@ export class Player extends Actor {
13691369
);
13701370
if (!wouldHitSolid && !wouldHitJumpThru) return;
13711371

1372-
this.y += dist;
1373-
this.clearVerticalRemainder();
1372+
this.moveVExact(dist);
13741373
}
13751374

13761375
private applyDashJumpThruNudge(): void {

tests/gameplay/dash-behavior.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { describe, expect, test } from "bun:test";
2+
import { WORLD } from "../../src/constants.ts";
23
import type { LevelEntitySpec } from "../../src/entities/types.ts";
34
import {
45
buildWorld,
6+
createPlayer,
57
createPlayerOnFloor,
68
makeInput,
79
step,
@@ -101,4 +103,40 @@ describe("Dash behavior", () => {
101103
expect(jump.snapshot.vx).toBeCloseTo(325, 5);
102104
expect(jump.snapshot.vy).toBeCloseTo(-52.5, 5);
103105
});
106+
107+
test("post-dash floor snap does not embed horizontal dashes in solid ground", () => {
108+
const floorRow = 20;
109+
const floorY = floorRow * WORLD.tile;
110+
const specs: LevelEntitySpec[] = [];
111+
withFloor(specs, floorRow);
112+
const world = buildWorld(specs);
113+
const player = createPlayer(world, 104, floorY - 4);
114+
115+
stepOnce(player, makeInput());
116+
stepOnce(player, makeInput({ x: 1, dashPressed: true }));
117+
118+
let landed = null as ReturnType<typeof player.getSnapshot> | null;
119+
for (let frame = 0; frame < 60; frame++) {
120+
const result = stepOnce(player, makeInput({ x: 1 }));
121+
if (result.snapshot.onGround && result.snapshot.state === "normal") {
122+
landed = result.snapshot;
123+
break;
124+
}
125+
}
126+
127+
expect(landed).toBeTruthy();
128+
expect(landed!.bottom).toBe(floorY);
129+
130+
const run = stepOnce(player, makeInput({ x: 1 })).snapshot;
131+
expect(run.x).toBeGreaterThan(landed!.x);
132+
expect(run.bottom).toBe(floorY);
133+
134+
const duck = stepOnce(player, makeInput({ y: 1 })).snapshot;
135+
expect(duck.isCrouched).toBeTrue();
136+
expect(duck.bottom).toBe(floorY);
137+
138+
const stand = stepOnce(player, makeInput()).snapshot;
139+
expect(stand.isCrouched).toBeFalse();
140+
expect(stand.bottom).toBe(floorY);
141+
});
104142
});

0 commit comments

Comments
 (0)