Skip to content

Commit 59eed32

Browse files
committed
refactor: extend Player class from Actor and streamline movement hooks
1 parent 4c1537d commit 59eed32

2 files changed

Lines changed: 206 additions & 123 deletions

File tree

src/player/Actor.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { Entity } from "../entities/core/Entity";
2+
import { CollisionWorld } from "../entities/CollisionWorld";
3+
import { addFloat, roundToEvenInt, sign, subFloat } from "./math";
4+
5+
export type MoveCollisionResult = "none" | "moved" | "break";
6+
7+
export abstract class Actor extends Entity {
8+
protected readonly world: CollisionWorld;
9+
10+
private remX = 0;
11+
private remY = 0;
12+
13+
protected constructor(x: number, y: number, world: CollisionWorld) {
14+
super(x, y);
15+
this.world = world;
16+
}
17+
18+
protected moveH(amount: number): boolean {
19+
this.remX = addFloat(this.remX, amount);
20+
const move = roundToEvenInt(this.remX);
21+
this.remX = subFloat(this.remX, move);
22+
return this.moveHExact(move);
23+
}
24+
25+
protected moveV(amount: number): boolean {
26+
this.remY = addFloat(this.remY, amount);
27+
const move = roundToEvenInt(this.remY);
28+
this.remY = subFloat(this.remY, move);
29+
return this.moveVExact(move);
30+
}
31+
32+
protected moveHExact(move: number): boolean {
33+
let collided = false;
34+
35+
while (move !== 0) {
36+
const step = sign(move);
37+
const nextX = this.x + step;
38+
39+
if (!this.world.collideAt(nextX, this.y, this.getMoveWidth(), this.getMoveHeight(), this.y, false)) {
40+
this.x = nextX;
41+
move -= step;
42+
continue;
43+
}
44+
45+
collided = true;
46+
const result = this.onCollideH(step);
47+
if (result === "moved") {
48+
move -= step;
49+
continue;
50+
}
51+
if (result === "break") {
52+
break;
53+
}
54+
55+
this.afterBlockedH(step);
56+
break;
57+
}
58+
59+
return collided;
60+
}
61+
62+
protected moveVExact(move: number): boolean {
63+
let collided = false;
64+
65+
while (move !== 0) {
66+
const step = sign(move);
67+
const nextY = this.y + step;
68+
69+
if (
70+
!this.world.collideAt(
71+
this.x,
72+
nextY,
73+
this.getMoveWidth(),
74+
this.getMoveHeight(),
75+
this.y,
76+
step > 0,
77+
)
78+
) {
79+
this.y = nextY;
80+
move -= step;
81+
continue;
82+
}
83+
84+
collided = true;
85+
const result = this.onCollideV(step);
86+
if (result === "moved") {
87+
move -= step;
88+
continue;
89+
}
90+
if (result === "break") {
91+
break;
92+
}
93+
94+
this.afterBlockedV(step);
95+
break;
96+
}
97+
98+
return collided;
99+
}
100+
101+
protected clearMovementRemainders(): void {
102+
this.remX = 0;
103+
this.remY = 0;
104+
}
105+
106+
protected clearHorizontalRemainder(): void {
107+
this.remX = 0;
108+
}
109+
110+
protected clearVerticalRemainder(): void {
111+
this.remY = 0;
112+
}
113+
114+
protected onCollideH(_step: number): MoveCollisionResult {
115+
return "none";
116+
}
117+
118+
protected onCollideV(_step: number): MoveCollisionResult {
119+
return "none";
120+
}
121+
122+
protected afterBlockedH(_step: number): void {
123+
}
124+
125+
protected afterBlockedV(_step: number): void {
126+
}
127+
128+
protected abstract getMoveWidth(): number;
129+
protected abstract getMoveHeight(): number;
130+
}

0 commit comments

Comments
 (0)