HUD 组件:血条、能量、分数、波次显示
> 109 行代码,把"状态"变成了"视觉信息"。
## 组件概览
`HUD` 是 NEON RUNNER 2077 里最"务实"的 UI 组件。它不搞花哨的故障效果,不做扫描线动画——它只做一件事:**把游戏状态实时显示在屏幕上**。
```ts
// src/ui/HUD.ts
export class HUD {
private healthBar: Phaser.GameObjects.Rectangle;
private healthBg: Phaser.GameObjects.Rectangle;
private energyBar: Phaser.GameObjects.Rectangle;
private energyBg: Phaser.GameObjects.Rectangle;
private scoreText: Phaser.GameObjects.Text;
private waveText: Phaser.GameObjects.Text;
private healthLabel: Phaser.GameObjects.Text;
private energyLabel: Phaser.GameObjects.Text;
```
## 布局:左上 + 右上
HUD 的布局非常对称:
- **左上角**:HP(血条)+ EN(能量条)
- **右上角**:SCORE(分数)+ WAVE(波次)
```ts
// 左上:HP
this.healthLabel = scene.add.text(40, 28, 'HP', {
fontFamily: FONTS.MONO, fontSize: '16px', color: '#00ff9d',
}).setDepth(100);
this.healthBg = scene.add.rectangle(80, 32, 220, 14, COLORS.DARK_LINE, 0.9)
.setOrigin(0, 0.5).setDepth(100).setStrokeStyle(1, COLORS.NEON_GREEN, 0.8);
this.healthBar = scene.add.rectangle(80, 32, 220, 14, COLORS.NEON_GREEN, 1)
.setOrigin(0, 0.5).setDepth(101);
```
注意 `healthBg` 和 `healthBar` 的位置完全重合,但 `healthBar` 的 `setDepth(101)` 比 `healthBg` 的 `setDepth(100)` 高一层——所以血条会覆盖在背景条之上。
## 血条:颜色随血量变化
```ts
setHealth(ratio: number): void {
const clamped = Phaser.Math.Clamp(ratio, 0, 1);
this.healthBar.width = 220 * clamped;
const color = clamped > 0.5
? COLORS.NEON_GREEN
: clamped > 0.25
? COLORS.NEON_ORANGE
: COLORS.NEON_MAGENTA;
this.healthBar.fillColor = color;
}
```
这是 HUD 里最有"信息量"的方法。血量变化时,不仅条的长度变化,**颜色也变化**:
- > 50%:绿色(安全)
- 25%-50%:橙色(警告)
- < 25%:品红(危险)
这个颜色变化是**无文字的状态提示**——玩家不需要看数字,一眼就知道自己还剩多少血。
## 能量条:只有长度变化
```ts
setEnergy(ratio: number): void {
const clamped = Phaser.Math.Clamp(ratio, 0, 1);
this.energyBar.width = 220 * clamped;
}
```
能量条比血条简单——只有长度变化,没有颜色变化。因为能量是"可恢复的"(`GameScene` 里每 1500ms 增加 0.04),不需要"警告"语义。
## 分数:六位零填充
```ts
setScore(score: number): void {
this.scoreText.setText(`SCORE ${String(score).padStart(6, '0')}`);
}
```
`String(score).padStart(6, '0')` 把分数格式化为 6 位数字,不足的前面补零。`SCORE 000000` → `SCORE 000123` → `SCORE 004567`。
这个"零填充"不是为了好看,而是**防止文字宽度抖动**。如果不用 `padStart`,`SCORE 123` 和 `SCORE 12345` 的宽度不同,会导致 `scoreText` 的 `setOrigin(1, 0)`(右对齐)位置偏移。
## 波次:两位零填充
```ts
setWave(wave: number): void {
this.waveText.setText(`WAVE ${String(wave).padStart(2, '0')}`);
}
```
同理,`WAVE 01`、`WAVE 02`、`WAVE 10`——两位数保证宽度一致。
## 销毁:清理所有对象
```ts
destroy(): void {
[
this.healthBar, this.healthBg, this.energyBar, this.energyBg,
this.scoreText, this.waveText, this.healthLabel, this.energyLabel,
].forEach((obj) => obj.destroy());
}
```
`GameScene` 的 `shutdown()` 里调用 `this.hud?.destroy()`。这个销毁是必要的——如果玩家从 `GameScene` 切回 `MenuScene` 再切回来,HUD 会被重新创建,如果不销毁旧的,屏幕上会有两套 HUD。
## 在 GameScene 中的初始化
```ts
this.hud = new HUD(this);
this.hud.setHealth(this.health);
this.hud.setEnergy(this.energy);
this.hud.setScore(this.score);
this.hud.setWave(this.wave);
```
HUD 在 `GameScene` 的 `create()` 里初始化,然后立即用当前状态(health=1, energy=0, score=0, wave=1)填充。
## 下一章预告
HUD 讲完了,但 NEON RUNNER 2077 的视觉风格真正爆发的地方是 `GameScene` 的 arena 背景。那个紫色网格 + 青色边框的背景是怎么画的?下一章我会拆解这个 122 行的场景。
> HUD 设计的核心原则:**信息密度 > 视觉花哨**。HUD 是"工具",不是"装饰"。玩家在战斗中不会去欣赏 HUD,只会用它读状态。
- 点赞
- 收藏
- 关注作者
评论(0)