1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
import { GAME_SIZE, PADDLE_HEIGHT, PADDLE_WIDTH, SessionState } from "../state";
import { VELOCITY_SCALING_FACTOR } from "./const";
import { Action, Collider } from "./types";
import { applyBallBounce, applyBallVelocity } from "./utils";
export const advanceState = async (
curState: SessionState,
action: Action | undefined
): Promise<SessionState> => {
//simulate network
await new Promise((res) => setTimeout(res, 15));
let candidatePaddle = curState.localPlayerGameState.paddle;
if (action === Action.MOVE_LEFT) {
candidatePaddle.position[0] = Math.max(0, candidatePaddle.position[0] - 1);
} else if (action === Action.MOVE_RIGHT) {
candidatePaddle.position[0] = Math.min(
GAME_SIZE.cols - 1 - PADDLE_WIDTH,
candidatePaddle.position[0] + 1
);
}
let candidateBricks = curState.localPlayerGameState.bricks;
const colliders: Collider[] = [];
//paddle collider
colliders.push({
normal: [0, -1],
boundingBox: [
{
min: candidatePaddle.position[0],
max: candidatePaddle.position[0] + PADDLE_WIDTH,
},
{
min: candidatePaddle.position[1],
max: candidatePaddle.position[1] + PADDLE_HEIGHT,
},
],
});
//brick colliders
candidateBricks.forEach(({ position }, i) => {
colliders.push({
boundingBox: position.map((pos) => ({
min: pos - 0.5,
max: pos + 0.5,
})) as Collider["boundingBox"],
normal: [0, 1],
onHit: () => candidateBricks.splice(i, 1),
});
});
//wall colliders
colliders.push(
...([
//left wall
{
boundingBox: [
{ min: -1, max: 0 },
{ min: 0, max: GAME_SIZE.rows },
],
normal: [1, 0],
},
//top wall
{
boundingBox: [
{ min: -1, max: GAME_SIZE.cols + 1 },
{ min: -1, max: 0 },
],
normal: [0, 1],
},
//right wall
{
boundingBox: [
{ min: GAME_SIZE.cols, max: GAME_SIZE.cols + 1 },
{ min: 0, max: GAME_SIZE.rows },
],
normal: [-1, 0],
},
] satisfies Collider[])
);
const candidateBalls = curState.localPlayerGameState.balls
.map((ball) => {
let candidateBall = applyBallVelocity(ball);
const hitCollider = colliders.find(({ boundingBox }) =>
candidateBall.position.every(
(pos, i) => pos >= boundingBox[i].min && pos <= boundingBox[i].max
)
);
if (hitCollider) {
hitCollider.onHit && hitCollider.onHit();
candidateBall = applyBallBounce(candidateBall, hitCollider.normal);
}
return candidateBall;
})
.filter((ball) => !!ball);
return {
...curState,
localPlayerGameState: {
...curState.localPlayerGameState,
bricks: candidateBricks,
paddle: candidatePaddle,
balls: candidateBalls,
},
};
};
|