# Boss 系统架构设计

> **关联切片**：S6 P0（Mini Boss Wave 8 / Final Boss Wave 20）
> **依赖系统**：EnemyManager、StatusManager、EventBus、VFXManager、ZoneManager

---

> **⚠️ 实现现状 (2026-07-20 审计)**：本文档描述的整套 Boss 架构（`BossManager` Autoload、`BossDef`/`BossPhaseDef`/`.tres` 资源、`BossAttackRegistry` 攻击模式注册表、场地机制如冰墙/场地收缩、多阶段弹幕、状态机 `BossInstance`）**均为设计蓝图，代码 0% 实现**。现状 Boss 只是 `EnemyManager` SoA 中 `type=4`（Mini Boss，Wave 8）/`type=5`（Final Boss，Wave 20）的普通厚血实体；唯一的"阶段行为"是当血量跨越 66% / 33% 阈值时召唤一批 `FAST` 杂兵援军（`wave_manager.gd:94-117`）。以下 `BossManager`/`.tres`/攻击模式注册表/场地机制全部尚未落地，保留作为未来实现的目标设计。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。

---

## 1. 设计原则

- **阶段驱动（Phase-Driven）**：Boss 行为由明确的阶段（Phase）枚举驱动，阶段切换在 `_physics_process` 中以血量阈值触发，不使用独立 Timer Node。
- **与 EnemyManager 解耦**：Boss 不进入 EnemyManager SoA（避免 stride 污染和 AI 逻辑膨胀），由独立的 `BossManager` Autoload 管理；但向 SpatialGrid 注册自身坐标，使子弹归航与 ZoneManager 能命中 Boss。
- **数据驱动**：每个 Boss 的阶段配置存储于 `.tres` Resource（`BossPhaseDef`），美术/策划可在不修改代码的情况下调整阈值与攻击模式。
- **EventBus 集成**：阶段切换、死亡均通过 EventBus 广播，HUD/BGM/成就系统订阅。

---

## 2. BossManager Autoload

```gdscript
# boss_manager.gd (Autoload: BossManager)
# Boss 实体数量极少（≤ 2 同屏），不使用 SoA，用 Array[BossInstance] 即可。

const MAX_BOSSES: int = 2   # 同屏 Boss 上限

var _active: Array[BossInstance] = []

func spawn_boss(boss_def_id: String, spawn_pos: Vector2) -> int:
    # 从 BossRegistry 加载 BossDef，实例化 BossInstance，注册到 SpatialGrid
    pass

func _physics_process(delta: float) -> void:
    for boss in _active:
        boss.tick(delta)
```

---

## 3. Phase 状态机模板

### 3.1 枚举与切换条件

每个 Boss 的阶段定义在 `BossPhaseDef` Resource 中：

```gdscript
# boss_phase_def.gd
class_name BossPhaseDef
extends Resource

@export var phase_id: int          # 阶段编号（0 起始）
@export var hp_threshold: float    # 进入此阶段的血量百分比（0.0~1.0），如 0.5 = 50% HP
@export var attack_patterns: Array[String]  # 此阶段可用的攻击模式 ID 列表
@export var move_speed_mult: float = 1.0    # 移动速度倍率（狂暴阶段可设 1.5）
@export var enrage_vfx: String = ""         # 阶段切换时触发的 VFX ID（空=无）
@export var phase_bgm_layer: int = 0        # 动态音乐层级（0=基础，1=紧张，2=狂暴）
```

### 3.2 BossInstance 状态机

```gdscript
# boss_instance.gd
class_name BossInstance
extends RefCounted

enum BossPhaseState {
    PHASE_0,    # 初始阶段（100% HP）
    PHASE_1,    # 受伤阶段（阈值由 BossDef 配置，通常 70%）
    PHASE_2,    # 危机阶段（通常 40%）
    PHASE_DYING # 死亡动画阶段（HP ≤ 0，播放死亡序列后才真正移除）
}

var boss_def: BossDef
var hp: float
var hp_max: float
var position: Vector2
var current_phase: BossPhaseState = BossPhaseState.PHASE_0
var _attack_cooldown: float = 0.0
var _pattern_index: int = 0       # 当前阶段攻击模式的轮询索引
var _phase_just_changed: bool = false  # 本帧刚切换阶段的标志，用于触发 enrage VFX

func tick(delta: float) -> void:
    _check_phase_transition()
    if current_phase == BossPhaseState.PHASE_DYING:
        _tick_dying(delta)
        return
    _tick_movement(delta)
    _tick_attack(delta)
    _sync_render()

# 血量阈值检查（每帧）
func _check_phase_transition() -> void:
    var hp_pct: float = hp / hp_max
    var phases: Array = boss_def.phases  # Array[BossPhaseDef]，按 hp_threshold 降序排列
    for i in phases.size():
        var phase_def: BossPhaseDef = phases[i]
        if hp_pct <= phase_def.hp_threshold and int(current_phase) < i + 1:
            _enter_phase(i + 1, phase_def)
            break

func _enter_phase(new_phase: int, phase_def: BossPhaseDef) -> void:
    current_phase = new_phase as BossPhaseState
    _pattern_index = 0
    _attack_cooldown = 0.0
    # 阶段切换 VFX
    if phase_def.enrage_vfx != "":
        VFXManager.play(phase_def.enrage_vfx, position, 1.0)
    # 通知 EventBus（HUD 高亮、BGM 切换）
    EventBus.emit(EventID.BOSS_PHASE_CHANGED, {
        "boss_id": boss_def.id,
        "phase": new_phase,
        "bgm_layer": phase_def.phase_bgm_layer
    })
```

---

## 4. 攻击模式系统 (Attack Pattern)

攻击模式以 ID 字符串存储，在 `BossAttackRegistry` 中注册（类比 `SpellRegistry`），运行时由 `_tick_attack` 调用：

```gdscript
# boss_instance.gd（续）
func _tick_attack(delta: float) -> void:
    _attack_cooldown -= delta
    if _attack_cooldown > 0.0:
        return
    var phase_def: BossPhaseDef = boss_def.phases[int(current_phase)]
    if phase_def.attack_patterns.is_empty():
        return
    # 轮询攻击模式
    var pattern_id: String = phase_def.attack_patterns[
        _pattern_index % phase_def.attack_patterns.size()
    ]
    _pattern_index += 1
    var cooldown: float = BossAttackRegistry.execute(pattern_id, self)
    _attack_cooldown = cooldown
```

`BossAttackRegistry.execute(id, boss)` 返回该攻击模式的冷却时间（秒）。每种攻击模式是一个独立的 GDScript 函数或 Resource，通过 SpellEvaluator 发射子弹（走标准 BulletManager 路径）。

---

## 5. 具体 Boss 设计模板

> **⚠️ 实现现状 (2026-07-20 审计)**：下表 HP 与阶段阈值均为**设计目标**，与代码现值不符。① **血量**：代码实取 `balance.json` 的 `boss_hp`（Mini=**450** / Final=**1800**，`balance.json:8-11`，疑为占位/待平衡值），并非本节的 2000 / 10000，也非 `numerical_design §3.2` 的 50000；三处数值互相矛盾。② **阶段阈值**：代码统一用 **66% / 33%** 两段（`wave_manager.gd:99-102`），并非本节 Mini 的 60%/30% 或 Final 的 70%/40%/15%。③ **攻击模式 / 场地机制 / move_speed / enrage_vfx** 字段全部未实现；每次"进阶"只是召唤 `4 + phase*2` 个 FAST 杂兵。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。

### 5.1 Mini Boss — Wave 8（待策划填充）

| 字段 | 值 |
| :--- | :--- |
| `boss_id` | `"mini_boss_w8"` |
| `hp_max` | 2000（约为普通精英 6.6×） |
| `move_speed` | 120（比杂鱼慢，靠范围攻击弥补） |
| **Phase 0**（100%→60% HP）| 攻击模式：`"charge_slam"` + `"spread_shot_3"` |
| **Phase 1**（60%→30% HP）| 追加：`"summon_minion_x2"`；move_speed_mult=1.2 |
| **Phase 2**（30%→0% HP）| 追加：`"zone_aoe_fire"`；move_speed_mult=1.5；enrage_vfx="boss_enrage" |
| 死亡事件 | `BOSS_KILLED`（**未实现**：该常量不存在；现状仅在生成时发 `BOSS_SPAWNED=19`，死亡走通用 `ENEMY_KILLED=7`）|
| 战场机制 | 无（Mini Boss 不设场地机制，Final Boss 才有）|

### 5.2 Final Boss — Wave 20（待策划填充）

| 字段 | 值 |
| :--- | :--- |
| `boss_id` | `"final_boss_w20"` |
| `hp_max` | 10000 |
| `move_speed` | 80（极慢，靠弹幕覆盖）|
| **Phase 0**（100%→70% HP）| 攻击模式：`"spiral_shot_8"` + `"summon_turrets_x4"` |
| **Phase 1**（70%→40% HP）| 追加：`"zone_ice_wall"`；场地：随机生成 4 个冰墙障碍（`ZoneManager` 驱动）|
| **Phase 2**（40%→15% HP）| 追加：`"enrage_laser_sweep"`；场地收缩：边界每 10 秒向中心缩小 50px |
| **Phase 3**（15%→0% HP）| 全弹幕覆盖；`"phase3_barrage"`；恢复部分 HP 后进入死亡序列（演出用）|
| 死亡事件 | **未实现**：`BOSS_KILLED` / `GAME_CLEARED` / `BOSS_PHASE_CHANGED` 三个常量均不存在（ID 15/16/17 实为 `SPELL_EQUIPPED`/`LEVEL_UP`/`SHOP_OPENED`）。现状：生成发 `BOSS_SPAWNED=19`，死亡走 `ENEMY_KILLED=7`，阶段切换发通用 `GAME_STATE_CHANGED=20`（payload `to="BOSS_PHASE_N"`）|
| 战场机制 | 场地收缩（Phase 2+）、冰墙障碍（Phase 1+）——**均未实现** |

---

## 6. EventBus 扩展（Boss 专用事件）

> **权威登记**：以下 ID 已并入 `technical/implementation_plan.md` §2.1 事件目录与 `event_ids.gd`，本节表为语义说明（勿改号）。

| 事件 ID | 常量名 | Payload | 订阅方 |
| :--- | :--- | :--- | :--- |
| 15 | `BOSS_PHASE_CHANGED` | `{boss_id, phase, bgm_layer}` | HUD（阶段提示）、AudioManager（BGM 切换）|
| 16 | `BOSS_KILLED` | `{boss_id, wave_num}` | WaveManager（进入结算）、AchievementManager |
| 17 | `GAME_CLEARED` | `{elapsed_sec, wave_num}` | GameCycleManager（结算屏）、排行榜 |

---

## 7. 与现有系统的接口约定

| 接口 | 调用方向 | 说明 |
| :--- | :--- | :--- |
| `SpatialGrid.register_boss(id, pos, radius)` | BossManager → SpatialGrid | Boss 作为可被子弹命中的实体，每帧更新坐标 |
| `BulletManager._on_bullet_hit(bullet_id, target_id)` | BulletManager → BossManager | `target_id` 前缀区分：`enemy_xxx` vs `boss_xxx`（或通过 faction 位掩码判断）|
| `ZoneManager.spawn_zone(...)` | BossAttackPattern → ZoneManager | Boss 攻击模式可生成 Zone（如冰墙、火圈）|
| `VFXManager.play(vfx_id, pos, scale)` | BossInstance → VFXManager | 阶段切换 + 死亡演出 VFX |
| `SpellEvaluator.execute_boss_pattern(pattern_id, origin)` | BossAttackRegistry → SpellEvaluator | Boss 弹幕走标准 SpellEvaluator 路径，复用子弹生成管线 |

---

## 8. 目录规范

```text
scripts/autoloads/
  boss_manager.gd          # Autoload BossManager
scripts/domain/boss/
  boss_def.gd              # class_name BossDef (Resource)
  boss_phase_def.gd        # class_name BossPhaseDef (Resource)
  boss_instance.gd         # class_name BossInstance (RefCounted)
  boss_attack_registry.gd  # BossAttackRegistry（类比 SpellRegistry）
resources/bosses/
  mini_boss_w8.tres
  final_boss_w20.tres
resources/boss_patterns/
  charge_slam.tres
  spread_shot_3.tres
  spiral_shot_8.tres
  # ...
```
