|
1 | 1 | import { Scene } from "phaser"; |
2 | 2 | import { depthsConfig } from "../configs"; |
| 3 | +import { GameHelper } from "../helpers"; |
3 | 4 | import { ArcadeBody, Sprite } from "../phaser-aliases"; |
4 | 5 | import { AnimationTag, EnnemyTag } from "../tags"; |
| 6 | +import { Hero } from "./hero.game-object"; |
| 7 | + |
| 8 | +export interface EnnemyConfig { |
| 9 | + scene: Scene; |
| 10 | + x: number; |
| 11 | + y: number; |
| 12 | + patrolDistance: number; |
| 13 | + chaseDistance: number; |
| 14 | + speed: number; |
| 15 | + sprite: EnnemyTag; |
| 16 | +} |
5 | 17 |
|
6 | 18 | export class Ennemy extends Sprite { |
7 | 19 | public declare body: ArcadeBody; |
8 | 20 |
|
| 21 | + private _patrolDistance: number; |
| 22 | + private _chaseDistance: number; |
| 23 | + private _player: Hero; |
| 24 | + private _startingX: number; |
| 25 | + private _spriteTag: EnnemyTag; |
| 26 | + private _patrolDirection = 1; |
9 | 27 | private _speed = 60; |
10 | | - private _startingPoint = { x: 0, y: 0 }; |
11 | | - private _endingPoint = { x: 0, y: 0 }; |
12 | | - private _isMovingToEnd = true; |
| 28 | + private _patrolTween: Phaser.Tweens.Tween | null = null; |
13 | 29 |
|
14 | | - constructor(private _scene: Scene, private _spriteTag: EnnemyTag) { |
15 | | - super(_scene, 0, 0, _spriteTag); |
| 30 | + private get _isPatrolling(): boolean { |
| 31 | + return this._patrolTween !== null; |
| 32 | + } |
16 | 33 |
|
17 | | - this.setDepth(depthsConfig.ennemies); |
| 34 | + constructor(config: EnnemyConfig, player: Hero) { |
| 35 | + super(config.scene, config.x, config.y, config.sprite); |
| 36 | + this._startingX = config.x; |
| 37 | + this._patrolDistance = config.patrolDistance; |
| 38 | + this._chaseDistance = config.chaseDistance; |
| 39 | + this._speed = config.speed; |
| 40 | + this._spriteTag = config.sprite; |
18 | 41 |
|
19 | | - this.createAnimations(); |
20 | | - } |
| 42 | + this._player = player; |
21 | 43 |
|
22 | | - public spawn(x: number, y: number): void { |
23 | 44 | this.scene.add.existing(this); |
24 | 45 | this.scene.physics.add.existing(this); |
25 | 46 |
|
26 | | - this.play(AnimationTag.ENNEMY_IDLE); |
27 | | - |
28 | 47 | this.flipX = true; |
29 | | - this.x = x; |
30 | | - this.y = y; |
31 | 48 |
|
32 | | - this._startingPoint = { x, y }; |
33 | | - } |
| 49 | + this.setDepth(depthsConfig.ennemies); |
34 | 50 |
|
35 | | - public patrol(endingPoint: { x: number; y: number }): void { |
36 | | - this._endingPoint = endingPoint; |
| 51 | + this.createAnimations(); |
| 52 | + this.startPatrol(); |
37 | 53 | this.play(AnimationTag.ENNEMY_MOVING); |
| 54 | + } |
38 | 55 |
|
39 | | - this._scene.events.on("update", () => { |
40 | | - if (this._isMovingToEnd) { |
41 | | - this.goToTarget(this._endingPoint.x, this._endingPoint.y); |
| 56 | + public update(): void { |
| 57 | + this.updateFlipX(); |
42 | 58 |
|
43 | | - const distance = Phaser.Math.Distance.Between(this.x, this.y, this._endingPoint.x, this._endingPoint.y); |
| 59 | + const distanceToPlayer = Phaser.Math.Distance.Between(this.x, this.y, this._player.x, this._player.y); |
44 | 60 |
|
45 | | - if (distance < 10) { |
46 | | - this._isMovingToEnd = false; |
47 | | - } |
48 | | - } else { |
49 | | - this.goToTarget(this._startingPoint.x, this._startingPoint.y); |
| 61 | + if (distanceToPlayer <= this._chaseDistance) { |
| 62 | + this.stopPatrol(); |
| 63 | + this.chasePlayer(); |
| 64 | + } // |
| 65 | + else if (distanceToPlayer > this._chaseDistance && this._patrolTween === null) { |
| 66 | + this.returnToStart(); |
| 67 | + } |
| 68 | + } |
50 | 69 |
|
51 | | - const distance = Phaser.Math.Distance.Between(this.x, this.y, this._startingPoint.x, this._startingPoint.y); |
| 70 | + private startPatrol(): void { |
| 71 | + if (this._patrolTween !== null) { |
| 72 | + return; |
| 73 | + } |
52 | 74 |
|
53 | | - if (distance < 10) { |
54 | | - this._isMovingToEnd = true; |
55 | | - } |
56 | | - } |
| 75 | + this._patrolDirection = Math.sign(this._patrolDistance); |
57 | 76 |
|
58 | | - this.flipX = this.body.velocity.x < 0; |
| 77 | + this._patrolTween = this.scene.tweens.add({ |
| 78 | + targets: this, |
| 79 | + x: this._startingX + this._patrolDistance, |
| 80 | + duration: Math.abs(this._patrolDistance) * 10, |
| 81 | + yoyo: true, |
| 82 | + repeat: -1, |
| 83 | + onYoyo: () => (this._patrolDirection *= -1), |
| 84 | + onRepeat: () => (this._patrolDirection *= -1), |
59 | 85 | }); |
60 | 86 | } |
61 | 87 |
|
62 | | - public goToTarget(targetX: number, targetY: number): void { |
63 | | - this.scene.physics.moveTo(this, targetX, targetY, this._speed); |
| 88 | + private stopPatrol(): void { |
| 89 | + if (this._patrolTween !== null) { |
| 90 | + this._patrolTween.stop(); |
| 91 | + this._patrolTween = null; |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + private chasePlayer(): void { |
| 96 | + const direction = Math.sign(this._player.x - this.x); |
| 97 | + this.body.setVelocityX(direction * this._speed); |
| 98 | + } |
| 99 | + |
| 100 | + private returnToStart(): void { |
| 101 | + if (!GameHelper.isCloseEnough(this.x, this._startingX)) { |
| 102 | + const direction = Math.sign(this._startingX - this.x); |
| 103 | + this.body.setVelocityX(direction * this._speed); |
| 104 | + } else { |
| 105 | + console.log("reached start"); |
| 106 | + this.body.setVelocityX(0); |
| 107 | + this.startPatrol(); |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + private updateFlipX(): void { |
| 112 | + // Patrol is using a tween, which updates X position instead of velocity |
| 113 | + if (this._isPatrolling) { |
| 114 | + this.setFlipX(this._patrolDirection < 0); |
| 115 | + } else { |
| 116 | + this.setFlipX(this.body.velocity.x < 0); |
| 117 | + } |
64 | 118 | } |
65 | 119 |
|
66 | 120 | private createAnimations(): void { |
|
0 commit comments