主题
09 · 街机射击:敌人波次与碰撞
目标:定时刷敌;用
overlap做子弹×敌人得分与玩家×敌人失败;对照阶段一手写 AABB。
前置:08 · 玩家移动与射击
1. 敌人 Group + 定时器
ts
private enemies!: Phaser.Physics.Arcade.Group
private score = 0
private gameOver = false
create() {
this.enemies = this.physics.add.group({
classType: Phaser.Physics.Arcade.Image,
maxSize: 30,
})
this.time.addEvent({
delay: 700,
loop: true,
callback: () => this.spawnEnemy(),
})
// 见下:overlap
}
private spawnEnemy() {
if (this.gameOver) return
const x = Phaser.Math.Between(30, 450)
const e = this.enemies.get(x, -20, 'enemy') as Phaser.Physics.Arcade.Image | null
if (!e) return
e.setActive(true).setVisible(true)
e.enableBody(true, x, -20, true, true)
e.setVelocity(0, Phaser.Math.Between(80, 140))
}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
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
对照 05:spawnTimer -= fixedDt ↔ time.addEvent({ delay, loop })。
2. overlap ≈ 引擎版 hit()
ts
this.physics.add.overlap(
this.bullets,
this.enemies,
(b, e) => this.onHitEnemy(
b as Phaser.Physics.Arcade.Image,
e as Phaser.Physics.Arcade.Image,
),
undefined,
this,
)
this.physics.add.overlap(
this.player,
this.enemies,
() => this.onPlayerHit(),
undefined,
this,
)
private onHitEnemy(
bullet: Phaser.Physics.Arcade.Image,
enemy: Phaser.Physics.Arcade.Image,
) {
this.bullets.killAndHide(bullet)
bullet.body?.stop()
this.enemies.killAndHide(enemy)
enemy.body?.stop()
this.score += 1
}
private onPlayerHit() {
this.gameOver = true
this.physics.pause()
}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
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
| 阶段一 | Phaser |
|---|---|
双重 for + hit(a,b) | physics.add.overlap |
splice 删除 | killAndHide / disableBody |
score += 1 | 同左 |
collider 会推挤分离;射击命中用 overlap(只回调,不弹开)更合适。
3. 出屏敌人也要回收
在 update 末尾:
ts
this.enemies.children.each((child) => {
const e = child as Phaser.Physics.Arcade.Image
if (!e.active) return true
if (e.y > 660) {
this.enemies.killAndHide(e)
e.body?.stop()
}
return true
})1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
漏回收 → Group 占满 maxSize → 再也刷不出怪,像「游戏坏了」。
4. gameOver 时停输入
ts
update(_t: number, delta: number) {
if (this.gameOver) return
// 移动、射击、回收……
}1
2
3
4
2
3
4
HUD 与 R 重启放 10。
验收清单
- [ ] 约每 0.7s 顶部刷出一个红敌机并下落
- [ ] 子弹打中敌人:双方消失,分数逻辑 +1(可先
console.log(score)) - [ ] 敌人碰玩家:进入
gameOver,物理暂停 - [ ] 敌机飞出底边被回收;长时间游玩 Group 不堵死
- [ ] 能向别人讲清 overlap 与阶段一 AABB 的对应关系
