Skip to content
This repository was archived by the owner on Jan 12, 2023. It is now read-only.

Commit 14cf90e

Browse files
committed
feat: reaycasting
1 parent 6386fe3 commit 14cf90e

File tree

2 files changed

+71
-35
lines changed

2 files changed

+71
-35
lines changed

ui/src/logic/game/game.ts

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import { Engine, World, Bodies, Query, Vector, Composite, Body } from "matter-js";
22
import { raycast } from "../../core/raycast";
33

4+
const frictionAir = .3;
5+
6+
export type BodyType = "wall" | "player" | "bullet" | "obstacle";
47

58
export type GameSettings = {
9+
ai: {
10+
sensorSidesArrayAngle: number[],
11+
sensorMaxRange: number,
12+
},
613
game: {
714
playerSize: number,
815
},
@@ -19,8 +26,10 @@ export type GameSettings = {
1926
export type GameInputPlayer = {
2027
walk: boolean,
2128
rotate: number,
22-
fire: boolean,
23-
switchWeapon: number,
29+
/** use item/fire weapon */
30+
use: boolean,
31+
/** select item/weapon */
32+
switch: number,
2433
};
2534

2635
export type GameInput = {
@@ -31,16 +40,16 @@ export type GameInput = {
3140
export type GameStatePlayer = {
3241
health: number,
3342
ammo: number[],
34-
weapon: {
43+
item: {
3544
/**
36-
* index of selected weapon
45+
* index of selected item/weapon
3746
*/
3847
selected: number,
3948
/**
40-
* after shooting this number is how to long it takes to shoot/swithch weapon again
49+
* after shooting this number is how to long it takes to shoot/use/swithch item/weapon again
4150
* 0 means shooting is possible
4251
*/
43-
relodingTime: number,
52+
cooldown: number,
4453
},
4554
position: {
4655
x: number,
@@ -56,6 +65,7 @@ export type GameState = {
5665

5766
const mergeSettings = (s: GameSettings, t: Partial<GameSettings>): GameSettings =>
5867
({
68+
ai: { ...s.ai, ...t?.ai },
5969
game: { ...s.game, ...t?.game },
6070
map: { ...s.map, ...t?.map },
6171
simulation: { ...s.simulation, ...t?.simulation },
@@ -71,11 +81,16 @@ export class Game {
7181
public mapping: {
7282
/** index of body in this array is same with index in game state */
7383
players: Matter.Body[],
84+
walls: Matter.Body[],
7485
};
7586

7687
public static readonly SETTINGS_DEFAULT: Readonly<GameSettings> = {
88+
ai: {
89+
sensorSidesArrayAngle: [Math.PI * 1 / 4, Math.PI * 1 / 8, Math.PI * 1 / 32],
90+
sensorMaxRange: 200,
91+
},
7792
map: {
78-
size: 200,
93+
size: 300,
7994
borders: 10,
8095
},
8196
game: {
@@ -101,7 +116,7 @@ export class Game {
101116

102117
const mergeInput = () => ({
103118
players: this.gameState.players.map((_, i) => ({
104-
fire: false, rotate: 0, switchWeapon: -1, walk: false,
119+
use: false, rotate: 0, switch: -1, walk: false,
105120
...(userInput?.players?.[i]),
106121
})),
107122
});
@@ -136,57 +151,75 @@ export class Game {
136151

137152
public sensor(playerIndex: number) {
138153
const {
139-
settings: { map: { size } },
154+
settings: {
155+
map: { size },
156+
ai: {
157+
sensorMaxRange, sensorSidesArrayAngle,
158+
} },
140159
gameState: { players },
141160
} = this;
142161
const player = players[playerIndex];
143162
const playerEngineBody = this.mapping.players[playerIndex];
144163

145-
const rayLengt = size * Math.pow(2, 1 / 2);
164+
const sensorAngles = [0]
165+
.concat(sensorSidesArrayAngle)
166+
.concat(sensorSidesArrayAngle.map(x => -x))
167+
.map(x => player.position.angle + x)
168+
;
146169

170+
const rayRange = Math.min(size * Math.pow(2, 1 / 2), sensorMaxRange);
147171
const playerVector = Vector.create(player.position.x, player.position.y);
148-
149172
const bodies = Composite.allBodies(this.world as any).filter(({ id }) => id !== playerEngineBody.id);
150-
return { point: raycast(bodies, playerVector, Vector.rotate(Vector.create(1, 0), player.position.angle), rayLengt)?.point };
173+
174+
return sensorAngles.map(x => {
175+
const ray = raycast(bodies, playerVector, Vector.rotate(Vector.create(1, 0), x), rayRange);
176+
if (!ray?.point)
177+
return Vector.add(playerVector, Vector.mult(Vector.normalise(Vector.rotate(Vector.create(1, 0), x)), rayRange));
178+
else
179+
return ray.point;
180+
});
151181
}
152182

153183
constructor(userSettings: Partial<GameSettings> = {}) {
154-
// create engine
155184
const settings = this.settings = mergeSettings(Game.SETTINGS_DEFAULT, userSettings);
156-
const engine = this.engine = Engine.create();
157-
185+
// create engine
186+
this.engine = Engine.create();
158187
const world = this.world;
159188

160189
world.gravity.y = 0;
161190

162191

163192
const { map: { size, borders }, game: { playerSize } } = settings;
164193
const center = size / 2;
165-
166-
World.add(world, Bodies.rectangle(0, center, borders * 2, size, { isStatic: true }));
167-
World.add(world, Bodies.rectangle(size, center, borders * 2, size, { isStatic: true, angle: Math.PI }));
168-
World.add(world, Bodies.rectangle(center, 0, size, borders * 2, { isStatic: true, angle: Math.PI }));
169-
World.add(world, Bodies.rectangle(center, size, size, borders * 2, { isStatic: true }));
170-
171194
const playerPadding = 5;
172195
const playerFromBorder = borders + playerSize + playerPadding;
173196

174197

175-
const frictionAir = .3;
176-
const p1 = Bodies.circle(size - playerFromBorder, playerFromBorder, playerSize, { frictionAir, angle: Math.PI * 3 / 4 });
177-
World.add(world, p1);
178-
const p2 = Bodies.circle(playerFromBorder, size - playerFromBorder, playerSize, { frictionAir, angle: Math.PI * (-1 / 4) });
179-
World.add(world, p2);
198+
199+
const walls = [
200+
Bodies.rectangle(0, center, borders * 2, size, { isStatic: true }),
201+
Bodies.rectangle(size, center, borders * 2, size, { isStatic: true, angle: Math.PI }),
202+
Bodies.rectangle(center, 0, size, borders * 2, { isStatic: true, angle: Math.PI }),
203+
Bodies.rectangle(center, size, size, borders * 2, { isStatic: true }),
204+
];
205+
World.add(world, walls);
206+
207+
const players = [
208+
Bodies.circle(size - playerFromBorder, playerFromBorder, playerSize, { frictionAir, angle: Math.PI * 3 / 4 }),
209+
Bodies.circle(playerFromBorder, size - playerFromBorder, playerSize, { frictionAir, angle: Math.PI * (-1 / 4) }),
210+
];
211+
World.add(world, players);
180212

181213
this.mapping = {
182-
players: [p1, p2],
214+
players,
215+
walls,
183216
};
184217

185218
this.gameState = {
186-
players: [p1, p2].map(({ position: { x, y }, angle }) =>
219+
players: players.map(({ position: { x, y }, angle }) =>
187220
({
188221
ammo: [], health: 1,
189-
weapon: { relodingTime: 0, selected: 0 },
222+
item: { cooldown: 0, selected: 0 },
190223
position: { x, y, angle },
191224
} as GameStatePlayer)),
192225
};

ui/src/views/Runner.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,16 @@ const Renderer: React.FC<TRendererProps> = ({ height, width }) => {
9393
});
9494

9595
Events.on(render, "afterRender", () => {
96-
const res = game.sensor(0);
97-
const playerPos = game.mapping.players[0].position;
96+
[0,1].forEach(pi=>{
97+
const res = game.sensor(pi);
98+
const playerPos = game.mapping.players[pi].position;
99+
100+
res.forEach(res => {
101+
renderPoint(render, res);
102+
renderLine(render, playerPos, res);
103+
});
104+
})
98105

99-
if (res?.point) {
100-
renderPoint(render, res.point);
101-
renderLine(render, playerPos, res.point);
102-
}
103106
});
104107

105108
keyCaptureStart();

0 commit comments

Comments
 (0)