8.4 KiB
8.4 KiB
Boss 系统架构设计
关联切片:S6 P0(Mini Boss Wave 8 / Final Boss Wave 20) 依赖系统:EnemyManager、StatusManager、EventBus、VFXManager、ZoneManager
1. 设计原则
- 阶段驱动(Phase-Driven):Boss 行为由明确的阶段(Phase)枚举驱动,阶段切换在
_physics_process中以血量阈值触发,不使用独立 Timer Node。 - 与 EnemyManager 解耦:Boss 不进入 EnemyManager SoA(避免 stride 污染和 AI 逻辑膨胀),由独立的
BossManagerAutoload 管理;但向 SpatialGrid 注册自身坐标,使子弹归航与 ZoneManager 能命中 Boss。 - 数据驱动:每个 Boss 的阶段配置存储于
.tresResource(BossPhaseDef),美术/策划可在不修改代码的情况下调整阈值与攻击模式。 - 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)
# 通知 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 调用:
# 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 设计模板
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(EventID 待分配,建议 ID=15) |
| 战场机制 | 无(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(EventID 16)+ GAME_CLEARED(17);阶段切换为 15(均以 implementation_plan.md §2.1 为准) |
| 战场机制 | 场地收缩(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. 目录规范
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
# ...