Files
spellforge/docs/technical/boss_design.md
T

11 KiB
Raw Blame History

Boss 系统架构设计

关联切片S6 P0Mini 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=4Mini BossWave 8/type=5Final BossWave 20)的普通厚血实体;唯一的"阶段行为"是当血量跨越 66% / 33% 阈值时召唤一批 FAST 杂兵援军(wave_manager.gd:94-117)。以下 BossManager/.tres/攻击模式注册表/场地机制全部尚未落地,保留作为未来实现的目标设计。详见 审计报告

更新 (2026-07-22):阶段状态机 + 7 种攻击模式(ring/spread/aimed/spiral/dash/charge_up/melee+ 敌方子弹(EnemyBulletManager+ BOSS_PHASE_CHANGED=29/BOSS_KILLED=30 事件已实现(BossManager autoload + data/bosses.json + 设计器 Boss 分页)。Boss 仍留在 EnemyManager SoA,移动由 BossManager 接管(非本文档 §2 的完全解耦方案)。仍未实现:场地机制(冰墙/收缩)、通关演出/GAME_CLEARED.tres(本工程纯 JSON)。


1. 设计原则

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

2. BossManager Autoload

# 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 中:

# 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 状态机

# 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)
    # 通知 EventBusHUD 高亮、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 调用:

# 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.jsonboss_hpMini=450 / Final=1800balance.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 杂兵。详见 审计报告

5.1 Mini Boss — Wave 8(待策划填充)

字段
boss_id "mini_boss_w8"
hp_max 2000(约为普通精英 6.6×)
move_speed 120(比杂鱼慢,靠范围攻击弥补)
Phase 0100%→60% HP 攻击模式:"charge_slam" + "spread_shot_3"
Phase 160%→30% HP 追加:"summon_minion_x2"move_speed_mult=1.2
Phase 230%→0% HP 追加:"zone_aoe_fire"move_speed_mult=1.5enrage_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 0100%→70% HP 攻击模式:"spiral_shot_8" + "summon_turrets_x4"
Phase 170%→40% HP 追加:"zone_ice_wall";场地:随机生成 4 个冰墙障碍(ZoneManager 驱动)
Phase 240%→15% HP 追加:"enrage_laser_sweep";场地收缩:边界每 10 秒向中心缩小 50px
Phase 315%→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=20payload 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(阶段提示)、AudioManagerBGM 切换)
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. 目录规范

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
  # ...