霓虹色板设计:从 colors.ts 到 CSS 变量的色彩系统
> 12 个色值,撑起整个赛博朋克世界的视觉基调。
## 颜色是赛博朋克的第一语言
打开 NEON RUNNER 2077,第一眼看到的不是玩法,而是颜色。深黑背景上的霓虹黄、青色、品红——这些颜色不是"好看"这么简单,它们是**信息编码**。
在 `src/config/colors.ts` 里,颜色被分成两套:
```ts
// 整数形式,用于 Phaser 的 fillStyle / strokeStyle
export const COLORS = {
NEON_YELLOW: 0xfcee0a,
NEON_CYAN: 0x00f0ff,
NEON_MAGENTA: 0xff003c,
NEON_PURPLE: 0xbd00ff,
NEON_ORANGE: 0xff6b00,
NEON_GREEN: 0x00ff9d,
DEEP_BLACK: 0x0a0a0f,
DARK_PANEL: 0x1a1a2e,
DARK_LINE: 0x2a2a3e,
WHITE: 0xffffff,
} as const;
// CSS 字符串形式,用于 DOM 样式
export const COLORS_CSS = {
NEON_YELLOW: '#FCEE0A',
NEON_CYAN: '#00F0FF',
// ... 其余相同
} as const;
```
为什么要有两套?因为 Phaser 的 `fillStyle()` 接收的是十六进制整数(`0xfcee0a`),而 CSS 的 `color` 属性接收的是字符串(`'#FCEE0A'`)。在同一个项目里维护两套色值,比到处硬编码强得多。
## 颜色语义:不是"红",而是"危险"
NEON RUNNER 2077 的色板不是随机选的,每个颜色都有明确的语义:
| 色值 | 十六进制 | 语义角色 |
|---|---|---|
| `NEON_YELLOW` | `#FCEE0A` | 标题、高亮、选中态 |
| `NEON_CYAN` | `#00F0FF` | 加载条、扫描线、次要信息 |
| `NEON_MAGENTA` | `#FF003C` | 危险、敌人、警告 |
| `NEON_PURPLE` | `#BD00FF` | 网格背景、氛围光 |
| `NEON_GREEN` | `#00FF9D` | 生命值、安全状态 |
| `NEON_ORANGE` | `#FF6B00` | 低血量警告 |
| `DEEP_BLACK` | `#0A0A0F` | 背景(不是纯黑,带一点蓝) |
| `DARK_PANEL` | `#1A1A2E` | 面板背景 |
| `DARK_LINE` | `#2A2A3E` | 分割线、边框 |
注意 `DEEP_BLACK` 不是 `#000000`,而是 `#0A0A0F`——带一点点蓝的黑色。这个细节让整个画面不会"死黑",在霓虹色照射下有微妙的反光感。
## 颜色在项目中的流动路径
一个颜色值从定义到最终显示,会经过三步:
**第一步:定义(colors.ts)**
```ts
NEON_CYAN: 0x00f0ff, // Phaser 用
NEON_CYAN: '#00F0FF', // CSS 用
```
**第二步:Phaser 场景中使用**
```ts
// PreloadScene.ts
g.fillStyle(0x00f0ff, 1); // 直接用整数
this.add.text(x, y, 'LOADING', { color: '#00F0FF' }); // 文字用字符串
```
**第三步:CSS 中使用**
```css
/* main.css */
:root {
--neon-cyan: #00f0ff;
}
.boot-sub {
color: var(--neon-cyan);
}
```
这种三层映射(TS 常量 → Phaser 调用 → CSS 变量)的好处是:**改一个地方,全项目同步**。如果想把霓虹青换成霓虹蓝,只改 `colors.ts` 里的 `0x00f0ff` 和 `'#00F0FF'` 两处。
## 颜色在 HUD 中的动态变化
HUD 的血条是最能体现颜色语义的例子:
```ts
// HUD.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;
}
```
血量 > 50% 时是绿色(安全),25%-50% 时是橙色(警告),< 25% 时是品红(危险)。这个颜色变化不需要任何文字提示,玩家一眼就能读懂状态。
## 颜色与 CSS 变量的联动
`main.css` 里的 `:root` 块把 `colors.ts` 里的色值暴露给整个 DOM:
```css
:root {
--neon-yellow: #fcee0a;
--neon-cyan: #00f0ff;
--neon-magenta: #ff003c;
/* ... */
}
```
这些变量被用在 `boot-overlay` 的故障文字动画里:
```css
.boot-text {
color: var(--neon-yellow);
text-shadow: 2px 0 var(--neon-magenta), -2px 0 var(--neon-cyan);
}
```
`text-shadow` 里同时用了品红和青色——这就是"故障效果"的 CSS 实现:两个偏移的阴影层,制造出 RGB 分离的错觉。
## 下一章预告
颜色定调了,但光有颜色不够,还需要**字体**。下一章我会拆解 `fonts.ts` 里那三个 Google Fonts 的选择逻辑——为什么是 Orbitron、Rajdhani 和 Share Tech Mono,以及它们是怎么在 Phaser 和 CSS 之间建立映射的。
> 颜色系统的核心原则:**语义优先于审美**。一个颜色值在代码里出现的地方越少,你的视觉系统就越稳定。
- 点赞
- 收藏
- 关注作者
评论(0)