Skip to content

Commit 41752b3

Browse files
committed
- raycasting to detect hero
1 parent f140ebd commit 41752b3

File tree

12 files changed

+98
-52
lines changed

12 files changed

+98
-52
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"dependencies": {
2323
"phaser": "^3.87.0",
2424
"phaser-animated-tiles": "^2.0.2",
25+
"phaser-raycaster": "^0.10.11",
2526
"rxjs": "^7.8.1"
2627
},
2728
"devDependencies": {

src/game-objects/ennemy.game-object.ts

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { Scene } from "phaser";
1+
import { CustomScene } from "@game-types";
22
import { depthsConfig } from "../configs";
33
import { GameHelper } from "../helpers";
44
import { ANIMATION, ArcadeBody, ArcadeSprite } from "../phaser-aliases";
55
import { AnimationTag, EnnemyTag, SfxTag } from "../tags";
66
import { Hero } from "./hero.game-object";
77

88
export interface EnnemyConfig {
9-
scene: Scene;
9+
scene: CustomScene;
1010
x: number;
1111
y: number;
1212
chaseDistance: number;
@@ -28,6 +28,16 @@ export class Ennemy extends ArcadeSprite {
2828
return this._config.speed;
2929
}
3030

31+
public get direction(): number {
32+
return this._direction;
33+
}
34+
protected debugGraphics: Phaser.GameObjects.Graphics;
35+
36+
protected set direction(value: number) {
37+
this._direction = value;
38+
this.setFlipX(value < 0);
39+
}
40+
3141
private _player: Hero;
3242
private _config: EnnemyConfig;
3343
private _isAttacking = false;
@@ -43,8 +53,13 @@ export class Ennemy extends ArcadeSprite {
4353
return this.scene.physics;
4454
}
4555

56+
private _raycaster: Raycaster;
57+
private _ray: Raycaster.Ray;
58+
4659
constructor(config: EnnemyConfig, player: Hero) {
4760
super(config.scene, config.x, config.y, config.sprite);
61+
this.debugGraphics = this.scene.add.graphics();
62+
4863
this._config = config;
4964

5065
this._player = player;
@@ -80,28 +95,38 @@ export class Ennemy extends ArcadeSprite {
8095
this
8196
);
8297

83-
this._direction = Phaser.Math.Distance.Between(this.x, this.y, this._player.x, this._player.y) > 0 ? 1 : -1;
98+
this.direction = Phaser.Math.Distance.Between(this.x, this.y, this._player.x, this._player.y) > 0 ? 1 : -1;
8499

85100
this.startPatrol();
101+
const plugin: PhaserRaycaster = this._config.scene.raycasterPlugin;
102+
103+
this._raycaster = plugin.createRaycaster({
104+
debug: false,
105+
});
106+
this.scene.physics.world.staticBodies.entries.forEach((body) => this._raycaster.mapGameObjects(body.gameObject));
107+
this._raycaster.mapGameObjects(this._player, true);
108+
109+
this._ray = this._raycaster.createRay();
110+
this._ray.setRayRange(this._config.chaseDistance);
111+
// this._ray.setRayRange(1000);
86112
}
87113

88114
public update(_: number, __: number): void {
89115
if (this._config.hp <= 0 || this._isAttacking) {
90116
return;
91117
}
92118

93-
this.updateFlipX();
94-
95119
const distanceToPlayer = GameHelper.getEdgeToEdgeDistance(this, this._player);
96120

97121
if (distanceToPlayer <= this._config.range) {
122+
this.stopPatrol();
98123
this.attack();
99124
} //
100-
else if (distanceToPlayer <= this._config.chaseDistance) {
125+
else if (this.heroIsInSight()) {
101126
this.stopPatrol();
102127
this.chasePlayer();
103128
} //
104-
else if (distanceToPlayer > this._config.chaseDistance && !this._isPatrolling) {
129+
else if (!this._isPatrolling) {
105130
this.startPatrol();
106131
}
107132

@@ -139,7 +164,7 @@ export class Ennemy extends ArcadeSprite {
139164
return;
140165
}
141166
const speed = this._isPatrolling ? this._config.patrolSpeed : this._config.speed;
142-
this.body.setVelocityX(speed * this._direction);
167+
this.body.setVelocityX(speed * this.direction);
143168
});
144169
}
145170

@@ -148,7 +173,7 @@ export class Ennemy extends ArcadeSprite {
148173

149174
GameHelper.animate(this, AnimationTag.ENNEMY_MOVING);
150175

151-
this.body.setVelocityX(this._config.patrolSpeed * this._direction);
176+
this.body.setVelocityX(this._config.patrolSpeed * this.direction);
152177
}
153178

154179
private stopPatrol(): void {
@@ -157,8 +182,8 @@ export class Ennemy extends ArcadeSprite {
157182

158183
private updatePatrol(): void {
159184
if (GameHelper.isObstacleAhead(this, this.scene) || GameHelper.isLedgeAhead(this, this.scene)) {
160-
this._direction *= -1;
161-
this.body.setVelocityX(this._config.patrolSpeed * this._direction);
185+
this.direction *= -1;
186+
this.body.setVelocityX(this._config.patrolSpeed * this.direction);
162187
}
163188
}
164189

@@ -170,7 +195,7 @@ export class Ennemy extends ArcadeSprite {
170195
this.scene.sound.play(SfxTag.PIXIE_ATTACK);
171196

172197
const hitboxPosition = {
173-
x: this.x + this._direction * this._attackHitbox.width,
198+
x: this.x + this.direction * this._attackHitbox.width,
174199
y: this.y,
175200
};
176201

@@ -200,27 +225,22 @@ export class Ennemy extends ArcadeSprite {
200225
});
201226
}
202227

203-
private chasePlayer(): void {
204-
this._direction = Math.sign(this._player.x - this.x);
205-
this.body.setVelocityX(this._direction * this._config.speed);
206-
}
228+
private heroIsInSight(): boolean {
229+
this._ray.setOrigin(this.x, this.y);
230+
this._ray.setAngleDeg(this._direction === 1 ? 0 : 180);
231+
this._ray.setConeDeg(this._isPatrolling ? 30 : 90);
232+
const result = this._ray.castCone();
207233

208-
private updateFlipX(): void {
209-
// Patrol is using a tween, which updates X position instead of velocity
210-
if (this._isPatrolling) {
211-
this.setFlipX(this._direction < 0);
212-
} //
213-
else {
214-
const distanceToPlayer = Phaser.Math.Distance.Between(this.x, this.y, this._player.x, this._player.y);
215-
216-
if (distanceToPlayer <= this._config.chaseDistance) {
217-
this._direction = Math.sign(this._player.x - this.x);
218-
this.setFlipX(this._direction < 0);
219-
} //
220-
else {
221-
this.setFlipX(this.body.velocity.x < 0);
234+
return result.some((line) => {
235+
if ("object" in line) {
236+
return line.object instanceof Hero;
222237
}
223-
}
238+
});
239+
}
240+
241+
private chasePlayer(): void {
242+
this.direction = Math.sign(this._player.x - this.x);
243+
this.body.setVelocityX(this.direction * this._config.speed);
224244
}
225245

226246
private setbodySize(params: { isAttacking: boolean }): void {

src/game-objects/hero.game-object.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ export class Hero extends ArcadeSprite {
5959
constructor(scene: Scene) {
6060
super(scene, 0, 0, SpritesheetTag.HERO);
6161

62-
this.setScale(0.5).setDepth(depthsConfig.hero);
63-
64-
// this.setCollideWorldBounds(true);
62+
this.setScale(0.6).setDepth(depthsConfig.hero);
6563

6664
if (!this.scene.input.keyboard) {
6765
throw Error("Keyboard plugin is not available");
@@ -82,6 +80,7 @@ export class Hero extends ArcadeSprite {
8280
public spawn(x: number, y: number): void {
8381
this.scene.add.existing(this);
8482
this.scene.physics.add.existing(this);
83+
this.scene.physics.world.enable(this);
8584

8685
this.x = x;
8786
this.y = y;

src/helpers/game.helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class GameHelper {
123123
debugGraphics.strokeRect(checkX, checkY, 2, 2);
124124

125125
scene.time.addEvent({
126-
delay: 1000,
126+
delay: 1,
127127
callback: () => debugGraphics.destroy(),
128128
callbackScope: this,
129129
loop: false,

src/helpers/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export * from './animations.manager';
2-
export * from './function';
3-
export * from './game.helper';
4-
export * from './hero.state';
5-
export * from './systems.helper';
1+
export * from "./animations.manager";
2+
export * from "./function";
3+
export * from "./game.helper";
4+
export * from "./hero.state";
5+
export * from "./systems.helper";

src/levels/level-1/1-forest.level.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { depthsConfig } from "@configs";
22
import { Ennemy, EnnemyConfig, Hero } from "@game-objects";
3+
import { CustomScene } from "@game-types";
34
import { GameHelper, isEnumValue } from "@helpers";
45
import { Sprite, Tilemap } from "@phaser-aliases";
56
import {
@@ -13,7 +14,6 @@ import {
1314
TilemapTag,
1415
TilesetTag,
1516
} from "@tags";
16-
import { Scene } from "phaser";
1717
import { ForestAnimations } from "./forest.animations";
1818

1919
type ValueOf<T> = T[keyof T];
@@ -85,7 +85,7 @@ export class ForestLevel {
8585

8686
private _animationsManager: ForestAnimations;
8787

88-
constructor(public hero: Hero, private _scene: Scene) {
88+
constructor(public hero: Hero, private _scene: CustomScene) {
8989
this._scene.sound.play(BackgroundSound.RIVER_FLOWING_INSECTS, {
9090
loop: true,
9191
volume: GameHelper.audioIsEnabled ? 1 : 0,
@@ -147,7 +147,7 @@ export class ForestLevel {
147147
layer?.setDepth(this._layersConfig[tag].depth);
148148
});
149149

150-
this._scene.sys.animatedTiles.init(this._map);
150+
this._scene.animatedTiles.init(this._map);
151151
}
152152

153153
private addColliders(): void {

src/main.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { PluginTag } from "@tags";
12
import { Game, Types } from "phaser";
3+
import AnimatedTiles from "phaser-animated-tiles/dist/AnimatedTiles.js";
4+
import PhaserRaycaster from "phaser-raycaster";
25
import { GameHelper } from "./helpers";
36
import { Boot, GameOver, Game as MainGame, MainMenu, Preloader } from "./scenes";
47

@@ -24,6 +27,20 @@ const config: Types.Core.GameConfig = {
2427
input: {
2528
keyboard: true,
2629
},
30+
plugins: {
31+
scene: [
32+
{
33+
key: PluginTag.RAYCASTER,
34+
plugin: PhaserRaycaster,
35+
mapping: PluginTag.RAYCASTER,
36+
},
37+
{
38+
key: PluginTag.ANIMATED_TILES,
39+
plugin: AnimatedTiles,
40+
mapping: PluginTag.ANIMATED_TILES,
41+
},
42+
],
43+
},
2744
scene: [Boot, Preloader, MainMenu, MainGame, GameOver],
2845
};
2946

src/scenes/game.scene.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
import { CustomScene } from "@game-types";
12
import { GameHelper } from "@helpers";
23
import { ANIMATION, Sprite } from "@phaser-aliases";
3-
import { Scene } from "phaser";
4-
import { AssetsConfig } from "../configs";
54
import { Hero } from "../game-objects";
65
import { ForestLevel } from "../levels";
76
import { AnimationTag, HeroEventTag, ImageTag, SceneTag, SpritesheetTag } from "../tags";
87

9-
export class Game extends Scene {
8+
export class Game extends CustomScene {
109
private _hero: Hero | undefined;
1110
private _keyboard: Phaser.Input.Keyboard.KeyboardPlugin | undefined;
1211
private _toggleDebugKey: Phaser.Input.Keyboard.Key | undefined;
@@ -20,12 +19,6 @@ export class Game extends Scene {
2019
super(SceneTag.GAME);
2120
}
2221

23-
public preload(): void {
24-
AssetsConfig.plugins.forEach((config) =>
25-
this.load.scenePlugin(config.tag, config.url, config.systemKey, config.sceneKey)
26-
);
27-
}
28-
2922
public create(): void {
3023
if (!this.input.keyboard) {
3124
throw Error("Keyboard plugin is not available");

src/tags/plugin.tag.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export enum PluginTag {
22
ANIMATED_TILES = "animatedTiles",
3+
RAYCASTER = "raycasterPlugin",
34
}

0 commit comments

Comments
 (0)