639 lines
30 KiB
Markdown
639 lines
30 KiB
Markdown
# 25 · 角色系统架构全景图
|
||
|
||
> **命名空间** `BaseGames.Player`、`BaseGames.Player.States`、`BaseGames.Enemies`、`BaseGames.Enemies.AI`、`BaseGames.Boss`、`BaseGames.Combat`
|
||
> **路径** `Assets/_Game/Scripts/Player/`、`Assets/_Game/Scripts/Enemies/`、`Assets/_Game/Scripts/Combat/`
|
||
> **关联文档** [05_PlayerModule](05_PlayerModule.md) · [06_CombatModule](06_CombatModule.md) · [07_EnemyModule](07_EnemyModule.md) · [09_ProgressionModule](09_ProgressionModule.md) · [23_BossSkillModule](23_BossSkillModule.md)
|
||
> **建立日期** 2026-05-17
|
||
|
||
本文档是跨模块的**角色系统实现全景图**,侧重三类角色(玩家 / 小怪 / Boss)在 Scene 中的节点结构、脚本职责划分、子系统数据流与相互协作关系。各模块深度细节请参阅上方关联文档。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [程序集依赖总览](#1-程序集依赖总览)
|
||
2. [玩家(Player)](#2-玩家-player)
|
||
- 2.1 [Scene 节点结构](#21-scene-节点结构)
|
||
- 2.2 [FSM 状态机](#22-fsm-状态机)
|
||
- 2.3 [数值体系 PlayerStats](#23-数值体系-playerstats)
|
||
- 2.4 [形态系统 Form System](#24-形态系统-form-system)
|
||
- 2.5 [武器系统 Weapon System](#25-武器系统-weapon-system)
|
||
- 2.6 [技能系统 Skill System](#26-技能系统-skill-system)
|
||
- 2.7 [能力解锁 AbilityType Flags](#27-能力解锁-abilitytype-flags)
|
||
- 2.8 [装备护符系统 Equipment / Charm](#28-装备护符系统-equipment--charm)
|
||
3. [小怪(Enemy)](#3-小怪-enemy)
|
||
- 3.1 [Scene 节点结构](#31-scene-节点结构)
|
||
- 3.2 [状态机(POCO 状态)](#32-状态机poco-状态)
|
||
- 3.3 [AI — Behavior Designer 节点库](#33-ai--behavior-designer-节点库)
|
||
4. [Boss](#4-boss)
|
||
- 4.1 [继承关系](#41-继承关系)
|
||
- 4.2 [Scene 节点结构](#42-scene-节点结构)
|
||
- 4.3 [技能执行流 BossSkillSO + BossSkillExecutor](#43-技能执行流-bossskillso--bossskillexecutor)
|
||
- 4.4 [阶段切换](#44-阶段切换)
|
||
5. [共享战斗层 Combat Module](#5-共享战斗层-combat-module)
|
||
- 5.1 [核心接口](#51-核心接口)
|
||
- 5.2 [HitBox → HurtBox 伤害流水线](#52-hitbox--hurtbox-伤害流水线)
|
||
- 5.3 [状态效果系统](#53-状态效果系统)
|
||
6. [数据驱动 ScriptableObject 体系](#6-数据驱动-scriptableobject-体系)
|
||
7. [架构核心原则总结](#7-架构核心原则总结)
|
||
|
||
---
|
||
|
||
## 1. 程序集依赖总览
|
||
|
||
```
|
||
BaseGames.Core
|
||
BaseGames.Core.Events
|
||
BaseGames.Core.Save
|
||
│
|
||
↓
|
||
BaseGames.Combat ──────────────────────────────────────────────┐
|
||
BaseGames.Combat.StatusEffects │
|
||
│ │
|
||
↓ ↓
|
||
BaseGames.Player BaseGames.Enemies │
|
||
BaseGames.Player.States BaseGames.Enemies.AI │
|
||
BaseGames.Skills BaseGames.Enemies.Navigation │
|
||
BaseGames.Equipment BaseGames.Enemies.Boss.Patterns │
|
||
BaseGames.Parry │
|
||
└────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**原则**:下层程序集不得引用上层。`BaseGames.Combat` 仅依赖 `Core`,`Player` / `Enemies` 均依赖 `Combat` 而不互相依赖。跨层通信一律通过 `EventChannelSO` 或 `ServiceLocator` 完成。
|
||
|
||
---
|
||
|
||
## 2. 玩家(Player)
|
||
|
||
### 2.1 Scene 节点结构
|
||
|
||
```
|
||
[Player] ← 根节点(空 GameObject,逻辑锚点)
|
||
│
|
||
├── PLY_Player ← 核心行为节点(所有主要组件挂于此)
|
||
│ │
|
||
│ │── PlayerController ← FSM 协调器(DefaultExecOrder=-100)
|
||
│ │ IDamageable + IPoiseSource
|
||
│ │── PlayerMovement ← 物理移动封装(DefaultExecOrder=-200)
|
||
│ │ Rigidbody2D 操作 / 土狼时间 / 地面检测
|
||
│ │── PlayerStats ← 数值管理(HP/灵魂/灵气/灵泉/LingZhu/能力Flags)
|
||
│ │ ISaveable + IRestoreOnSave + IRewardTarget
|
||
│ │── PlayerCombat ← 连击段 DamageSource 切换 / HitBox 激活接口
|
||
│ │── FormController ← 三形态状态机(天魂/地魂/命魂)
|
||
│ │── WeaponManager ← 依形态切换 ActiveWeapon + 实例化 HitBoxPrefab
|
||
│ │── SkillManager ← 技能槽管理 / 冷却计时 / 资源消耗
|
||
│ │── SpringSystem ← 灵泉治疗充能系统
|
||
│ │── ParrySystem ← 弹反时序窗口(见 CombatModule §10)
|
||
│ │── ShieldComponent ← 护盾吸收(IShieldable)
|
||
│ │── PlayerWallDetector ← 蹬墙感应(贴墙方向 / 触发 WallSlide 条件)
|
||
│ │── StatusEffectManager ← IStatusEffectable(火 / 毒 / 硬直效果接收)
|
||
│ │── EquipmentManager ← 护符槽管理(Notch 容量体系)
|
||
│ │── SkillModifierRegistry ← 护符注入的技能修改器(冷却/费用调节)
|
||
│ │── AnimancerComponent ← 动画驱动
|
||
│ │ Layer 0:全身状态动画(移动/攻击/受伤/死亡)
|
||
│ │ Layer 1(Overlay):叠加层动画(灵泉/法术)
|
||
│ │── InputBuffer ← 输入缓冲(RequireComponent by PlayerController)
|
||
│ │── Rigidbody2D ← Dynamic,FreezeRotation,插值关闭
|
||
│ └── CapsuleCollider2D ← isTrigger=false,碰撞体
|
||
│
|
||
├── HurtBox ← 受击盒(isTrigger=true,Layer=PlayerHurtBox)
|
||
│ └── HurtBox.cs GetComponentInParent<IDamageable>() 注入
|
||
│
|
||
├── [WeaponSocket] ← HitBox 挂载点(WeaponManager 实例化目标)
|
||
│ └── WeaponHitBoxInstance ← 由 WeaponSO.hitBoxPrefab 动态实例化/销毁
|
||
│ └── HitBox ← Layer=PlayerHitBox,isTrigger=true
|
||
│
|
||
├── GroundCheck ← 地面检测 Transform(BoxOverlapNonAlloc 起点)
|
||
│
|
||
└── SkillHitBox_Slot ← 技能命中盒挂载点(SkillHitBoxInstance 实例化)
|
||
```
|
||
|
||
> **命名规范**:根节点用 `[Player]`(方括号标识逻辑组节点),具体 GameObject 用 `PLY_` 前缀(PascalCase),子功能节点用 `[WeaponSocket]` 括号命名,检测点用描述性名称 `GroundCheck`。
|
||
|
||
---
|
||
|
||
### 2.2 FSM 状态机
|
||
|
||
`PlayerController` 持有 `Dictionary<Type, PlayerStateBase>` 状态字典,每帧驱动 `_currentState` 的 `OnStateUpdate / OnStateFixedUpdate`,并在 `TransitionTo<T>()` 时依次调用 `OnStateExit / OnStateEnter`。
|
||
|
||
```
|
||
PlayerStateBase(抽象 POCO,不继承 MonoBehaviour)
|
||
│ OnStateEnter / OnStateUpdate / OnStateFixedUpdate / OnStateExit
|
||
│ virtual bool IsInvincible → DashState override true
|
||
│ #if UNITY_EDITOR ValidTransitions → 转换白名单(调试用)
|
||
│
|
||
├── IdleState 落地重置 AirJumps;出口:Run / Jump / Dash / Attack / Spring
|
||
├── RunState 水平位移 + 朝向;出口同 Idle + WallSlide
|
||
├── JumpState 可变跳跃(松键截断 Y 速度)+ 土狼时间消耗
|
||
├── FallState FallMultiplier 下落加速;贴墙→WallSlide
|
||
├── DashState IsInvincible=true;地面冲刺 dashDistance / 冷却 dashCooldown
|
||
├── AerialDashState 空中冲刺消耗 _aerialDashCount;落地重置次数
|
||
├── WallSlideState wallSlideSpeed 减速下滑;Space → WallJump
|
||
├── WallJumpState 弹离墙壁 X+Y 分量;wallJumpLockTime 方向锁定
|
||
├── AttackState 3 段连击(Combo Window 计时);每段调 SetComboSegmentSource
|
||
├── AirAttackState 空中攻击,HitBox 朝正前方激活
|
||
├── UpAttackState 上劈,HitBox 朝正上方激活
|
||
├── DownAttackState 下劈 + OnDownHitConfirmed → trampolineForce 蹦跳反弹
|
||
├── HurtState hurtDuration 硬直;Initialize(DamageInfo) 注入伤害信息
|
||
├── DeadState 冻结 Rigidbody2D;触发 _onPlayerDied EventChannelSO
|
||
├── ParryState 弹反时序窗口(与 ParrySystem 协作)
|
||
├── SpringState 治疗动画;高优先级保护窗口防打断
|
||
└── SwimState 液体中自由移动(需解锁 AbilityType.Swim)
|
||
```
|
||
|
||
**关键设计决策**:
|
||
- 状态为 POCO 类,不持有 MonoBehaviour 生命周期开销,也不产生 GC(Dictionary 在 `Awake` 一次性填充)。
|
||
- `PlayerController` 在 `TakeDamage` 中先查询 `_currentState.IsInvincible`,后查 `_stats.IsInvincible`(无敌帧窗口),双层保护互不依赖。
|
||
- `#if UNITY_EDITOR` 转换白名单在 Editor 模式下帮助捕获非法状态跳转,运行时零开销剔除。
|
||
|
||
---
|
||
|
||
### 2.3 数值体系 PlayerStats
|
||
|
||
```
|
||
PlayerStats
|
||
├── ISaveable → 存读档(SaveManager 调用)
|
||
├── IRestoreOnSave → 存档触发时恢复(如灵泉数量)
|
||
└── IRewardTarget → RewardSO 颁奖接口(避免 Quest 直接依赖 Player 程序集)
|
||
|
||
运行时字段
|
||
├── HP / MaxHP TakeDamage / Heal / InvincibleTimer
|
||
├── SoulPower / Max 法术资源(攻击命中积累)
|
||
├── SpiritPower / Max 灵气资源(自动回复,SpiriRegenTimer 驱动)
|
||
├── SpringCharges / Max 灵泉治疗充能槽(SpringSystem 消耗)
|
||
├── LingZhu 货币(击杀 / 收集 / 购买)
|
||
├── AbilityType _unlockedAbilities [Flags] uint 位图,HasAbility(flag) O(1) 查询
|
||
│
|
||
├── 护符数值修改器
|
||
│ ├── _flatModifiers[StatType] 固定值加成(如 +5 MaxHP)
|
||
│ └── _percentModifiers[StatType] 百分比加成(如 +20% SoulPower)
|
||
│
|
||
├── AnimatorSpeedMultiplier 1f + _animatorSpeedBonus(护符注入攻速)
|
||
├── SoulCostReduction 法术费用减免(护符叠加)
|
||
│
|
||
└── 难度缩放
|
||
订阅 DifficultyChangedEventChannel
|
||
→ 按当前 HP 比例重算 MaxHP(保持 HP 比例不跳变)
|
||
```
|
||
|
||
---
|
||
|
||
### 2.4 形态系统 Form System
|
||
|
||
```
|
||
FormConfigSO(资产,Inspector 拖入 FormController)
|
||
└── FormSO[] forms
|
||
├── FormSO { formId="Form_Sky", formType=Sky, defaultWeapon=WeaponSO_SkyBlade }
|
||
├── FormSO { formId="Form_Earth", formType=Earth, defaultWeapon=WeaponSO_EarthHammer }
|
||
└── FormSO { formId="Form_Death", formType=Death, defaultWeapon=WeaponSO_DeathScythe }
|
||
|
||
FormController.SwitchForm(FormType)
|
||
│
|
||
├─ 1. IntEventChannelSO _onFormChanged.Raise(index)
|
||
│ → SaveSystem 持久化 ActiveFormId
|
||
│ → UI HUD 更新形态图标
|
||
│
|
||
├─ 2. C# event OnFormChanged
|
||
│ → WeaponManager.HandleFormChanged() ← OnEnable 订阅,OnDisable 退订
|
||
│
|
||
└─ 3. VoidEventChannelSO _onSkillSetChanged.Raise()
|
||
→ SkillHUD 刷新当前形态技能组图标
|
||
```
|
||
|
||
**护符 Override 流**:护符装备时调用 `WeaponManager.SetOverride(formId, weaponSO)` 覆盖指定形态的默认武器;卸下时调用 `ClearOverride(formId)` 还原,无需修改 `FormSO` 资产。
|
||
|
||
---
|
||
|
||
### 2.5 武器系统 Weapon System
|
||
|
||
```
|
||
WeaponSO(纯数据 SO)
|
||
├── 连击动画 attack1/2/3/air/up/downClip (Animancer ClipTransition)
|
||
├── 伤害来源 attack1/2/3/air/up/downSource (DamageSourceSO,各段独立配置)
|
||
├── hitBoxPrefab → WeaponHitBoxInstance + HitBox 碰撞体
|
||
└── soulPowerGain 命中后灵魂增加量(覆盖默认值)
|
||
|
||
WeaponManager(运行时)
|
||
│
|
||
│ FormController.OnFormChanged ──►
|
||
│ ApplyWeapon(FormSO)
|
||
│ ├── 检查 _overrides[formId](护符 Override 优先)
|
||
│ └── SetDirectWeapon(WeaponSO)
|
||
│ ├── Destroy 旧 HitBox GameObject
|
||
│ ├── Instantiate 新 hitBoxPrefab 到 [WeaponSocket]
|
||
│ └── OnWeaponChanged.Invoke(newWeapon)
|
||
│ └── PlayerCombat 订阅:刷新 _currentHitBoxInstance 引用
|
||
|
||
PlayerCombat
|
||
│
|
||
├── SetComboSegmentSource(comboIndex) ← AttackState 每段开始时调用
|
||
│ comboIndex 0/1/2 → attack1/2/3Source → HitBoxInstance.SetDamageSource
|
||
│
|
||
├── EnableWeaponHitBox(AttackDirection) ← 动画事件 / State 调用
|
||
│ GetSourceByDir → Activate(dir, source, ownerTransform)
|
||
│
|
||
└── OnDownHitConfirmed ← DownAttackState 订阅
|
||
命中时向上施加 trampolineForce
|
||
```
|
||
|
||
---
|
||
|
||
### 2.6 技能系统 Skill System
|
||
|
||
```
|
||
FormSkillSO(CreateAssetMenu: BaseGames/Skills/FormSkill)
|
||
│
|
||
├── Identity skillId / displayNameKey / icon
|
||
├── Resource resourceType(SoulPower | SpiritPower)/ baseCost / cooldown
|
||
├── Animation castAnimation(ClipTransition)/ castLockDuration(施放锁定秒数)
|
||
├── Effect effectType(MeleeAoE / Projectile / BarrierAura / WraithDash /
|
||
│ GroundDive / DragonKick / ShadowDecoy / DelayedExplosion)
|
||
├── Projectile projectileConfig / isHoming / holdForContinuous
|
||
├── Dash dashForce / dashDuration / isInvincibleDuringDash
|
||
├── Explosion explosionDelay / explosionRadius
|
||
├── Feedback castFeedback(FeedbackPresetSO)
|
||
└── hitBoxPrefab → 近战/爆炸技能命中盒(SkillHitBoxInstance + HitBox)
|
||
|
||
SkillManager(BaseGames.Skills 程序集)
|
||
├── FormSkillSO[] _slots 按 SkillSlotNames 枚举索引
|
||
├── SkillModifierRegistry _mods 护符注入的冷却/费用修改器
|
||
├── float[] _cooldownTimers 每槽独立冷却计时
|
||
└── ExecuteSkill(slotIndex)
|
||
├── 检查冷却 / 资源(baseCost - SoulCostReduction)
|
||
├── PlayerStats.SpendResource(type, cost)
|
||
├── Animancer.Play(castAnimation) + 锁定输入 castLockDuration 秒
|
||
└── 依 effectType 分支执行:投射物 / AoE HitBox / Dash / 爆炸延迟 …
|
||
```
|
||
|
||
---
|
||
|
||
### 2.7 能力解锁 AbilityType Flags
|
||
|
||
```csharp
|
||
[Flags] enum AbilityType : uint
|
||
{
|
||
None = 0,
|
||
// 移动
|
||
WallCling = 1u << 0, // 贴墙悬挂
|
||
WallJump = 1u << 1, // 墙跳
|
||
Dash = 1u << 2, // 地面冲刺
|
||
AirDash = 1u << 3, // 空中二段冲刺
|
||
DoubleJump = 1u << 4, // 二段跳
|
||
SuperJump = 1u << 5, // 聚气超跳
|
||
Swim = 1u << 6, // 液体游泳
|
||
Dive = 1u << 7, // 下劈
|
||
// 法术
|
||
Spell1/2/3 = 1u << 8~10,
|
||
// 形态
|
||
SpiritForm = 1u << 11,
|
||
SpiritDash = 1u << 12,
|
||
// 战斗
|
||
Parry = 1u << 13,
|
||
ChargeAttack = 1u << 14,
|
||
DownSlash = 1u << 15,
|
||
// 互动
|
||
Interact = 1u << 16,
|
||
FastTravel = 1u << 17,
|
||
// 强化
|
||
InvincibleDash = 1u << 18, // Dash 无敌帧强化
|
||
}
|
||
```
|
||
|
||
- `PlayerStats.HasAbility(flag)` → O(1) 位与运算,无分支列表遍历。
|
||
- 状态类在 `OnStateEnter` 或 `GetNextState` 中调用 `Stats.HasAbility(AbilityType.WallJump)` 等判断是否允许转换。
|
||
- `AbilityManager`(Progression 模块)解锁时调用 `PlayerStats.UnlockAbility(flag)` 并写入存档。
|
||
|
||
---
|
||
|
||
### 2.8 装备护符系统 Equipment / Charm
|
||
|
||
```
|
||
CharmSO
|
||
├── notchCost Notch 槽位消耗量
|
||
└── ICharmEffect[] effects
|
||
├── OnEquip(EquipmentContext)
|
||
│ 可修改:PlayerStats 数值 / WeaponManager Override / SkillModifierRegistry
|
||
└── OnUnequip(EquipmentContext)
|
||
还原所有修改(避免副作用残留)
|
||
|
||
EquipmentContext(注入包,Awake 时构建)
|
||
├── PlayerStats
|
||
├── PlayerFeedback
|
||
├── SkillModifierRegistry
|
||
└── WeaponManager
|
||
|
||
EquipmentManager(ISaveable)
|
||
├── _currentNotchCapacity 初始值来自 EquipmentConfigSO,可解锁扩容
|
||
├── _usedNotches 缓存值(避免每次 LINQ Sum)
|
||
├── TryEquipCharm(charm) 容量检查 → fx.OnEquip → 事件广播
|
||
├── UnequipCharm(charm) fx.OnUnequip → 事件广播
|
||
│
|
||
└── 事件频道
|
||
├── CharmEventChannelSO _onCharmEquipped
|
||
├── CharmEventChannelSO _onCharmUnequipped
|
||
└── VoidEventChannelSO _onEquipmentChanged → UI 刷新
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 小怪(Enemy)
|
||
|
||
### 3.1 Scene 节点结构
|
||
|
||
```
|
||
[Enemy_SpiderGuard] ← 根节点(挂 EnemyBase 或具体子类)
|
||
│ EnemyBase(或 RangedEnemy / FlyingEnemy)
|
||
│ ├── EnemyStats 运行时 HP / Defense / AttackCooldown
|
||
│ │ Initialize(EnemyStatsSO) 注入;难度缩放订阅
|
||
│ ├── EnemyMovement Rigidbody2D 封装
|
||
│ │ MoveHorizontal / FaceTarget / Knockback / JumpTo
|
||
│ ├── EnemyCombat 攻击范围 / 伤害触发(近战/弹幕调度)
|
||
│ ├── EnemyFeedback 受击闪烁 / 音效 / HitStop / 受击特效
|
||
│ ├── EnemyPoiseComponent IPoiseSource 实现(霸体等级声明)
|
||
│ ├── AnimancerComponent
|
||
│ ├── BehaviorTree Opsive Behavior Designer 资产绑定
|
||
│ └── EnemyNavAgent IPathAgent 实现(PathBerserker2D waypoint/jump 寻路)
|
||
│
|
||
├── HurtBox isTrigger=true,Layer=EnemyHurtBox
|
||
│
|
||
├── HitBox_Melee isTrigger=true,Layer=EnemyHitBox
|
||
│ └── HitBox.cs
|
||
│
|
||
└── BodyContactDamage(可选) 碰撞体直接造成接触伤害
|
||
```
|
||
|
||
**子类扩展**:
|
||
- `RangedEnemy`:额外持有 `ProjectileManager` 引用 / 弹幕发射逻辑覆盖
|
||
- `FlyingEnemy`:禁用地面检测,使用独立飞行移动逻辑
|
||
|
||
---
|
||
|
||
### 3.2 状态机(POCO 状态)
|
||
|
||
```
|
||
EnemyStateType(枚举)+ Dictionary<EnemyStateType, IEnemyState>
|
||
|
||
IEnemyState
|
||
├── StateType 枚举值(字典键)
|
||
├── Enter(EnemyBase owner)
|
||
└── Exit(EnemyBase owner)
|
||
|
||
具体状态
|
||
├── EnemyControlledState 正常 AI 驱动(Behavior Tree 运行中)
|
||
├── EnemyHurtState 受击硬直(播放受击动画,短暂停止 BD)
|
||
├── EnemyStaggerState 霸体破防强硬直(较长,期间 BD 暂停)
|
||
└── EnemyDeadState 死亡(IsAlive=false / 关闭碰撞体 / 播放死亡动画 / 掉落战利品)
|
||
```
|
||
|
||
**TakeDamage 伤害判定流**:
|
||
|
||
```
|
||
EnemyBase.TakeDamage(DamageInfo)
|
||
├── if Dead → return
|
||
├── EnemyStats.TakeDamage(finalDamage)
|
||
├── EnemyFeedback.OnHit(info) 受击视觉/音效反馈
|
||
├── if HP <= 0 → Die()
|
||
└── else
|
||
├── 比较 info.PoiseBreak vs EnemyPoiseComponent.CurrentPoiseLevel
|
||
├── PoiseBreak ≥ CurrentPoise → ForceState(Stagger)
|
||
├── PoiseBreak < CurrentPoise → ForceState(Hurt)(仅 Feedback,不打断 BD)
|
||
└── 霸体完全抵抗 → 仅 Feedback(受击特效,BD 不中断)
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 AI — Behavior Designer 节点库
|
||
|
||
所有 BD 节务类位于 `Assets/_Game/Scripts/Enemies/AI/`,前缀 `BD_`:
|
||
|
||
| 分类 | 任务类 | 功能 |
|
||
|------|--------|------|
|
||
| **感知** | `BD_IsPlayerVisible` | BatchLOSSystem 查询视线(批量 Raycast,Burst 加速) |
|
||
| | `BD_IsPlayerInRange` | `EnemyStats.SqrDistanceToPlayer < range²`(避免 sqrt) |
|
||
| | `BD_IsHPBelow` | `EnemyStats.CurrentHP / MaxHP < ratio` |
|
||
| | `BD_IsNearEdge` | 边缘检测(防坠落巡逻) |
|
||
| | `BD_IsGrounded` | 地面状态查询 |
|
||
| | `BD_IsStateMatch` | 查询当前 EnemyStateType |
|
||
| **移动** | `BD_MoveTo` | 目标点直线移动(EnemyNavAgent) |
|
||
| | `BD_MoveToPlayer` | 追击玩家位置 |
|
||
| | `BD_Patrol` | 往返巡逻(PatrolPoints[] 路径点) |
|
||
| | `BD_JumpTo` | 抛物线跳跃到目标位置 |
|
||
| | `BD_TeleportTo` | 瞬移(Boss 阶段过渡用) |
|
||
| | `BD_StopMovement` | 停止水平速度 |
|
||
| | `BD_FaceTarget` | 朝向玩家/目标 |
|
||
| **战斗** | `BD_Attack` | 触发近战攻击(EnemyCombat) |
|
||
| | `BD_CanAttack` | 攻击冷却检查(AttackCooldownTimer <= 0) |
|
||
| | `BD_SpawnProjectile` | 生成投射物(ProjectileManager) |
|
||
| | `BD_TelegraphAttack` | 激活 TelegraphSystem 预兆提示 |
|
||
| **特殊** | `BD_SummonMinions` | 召唤小怪(Boss 用) |
|
||
| | `BD_EnterPhase` | 调用 BossBase.EnterPhase(phase) |
|
||
| | `BD_SetAlert` | 设置警觉状态标记(影响巡逻/追击切换) |
|
||
| **动画** | `BD_PlayAnimation` | Animancer 播放指定 Clip |
|
||
| | `BD_WaitForAnimation` | 等待当前动画播放完毕 |
|
||
| **时序** | `BD_Wait` | 等待固定秒数 |
|
||
| | `BD_WaitRandom` | 等待随机时长(min~max) |
|
||
|
||
`BatchLOSSystem`:单例系统,每帧收集所有 `ILOSRequester` 的视线查询,批量执行 Raycast(可选 Burst Job),结果写回各敌人缓存,避免 N 个敌人同帧各自独立 Physics2D.Raycast 的性能峰值。
|
||
|
||
---
|
||
|
||
## 4. Boss
|
||
|
||
### 4.1 继承关系
|
||
|
||
```
|
||
MonoBehaviour
|
||
└── EnemyBase(IDamageable / ILOSRequester)
|
||
└── BossBase
|
||
├── 多阶段切换:EnterPhase(int) + BossPhaseEventChannelSO 广播
|
||
├── IsHPBelow(float ratio) → BD_IsHPBelow 轮询条件
|
||
└── override Die() → _onBossFightEnded.Raise(true)
|
||
└── [具体 Boss 类]
|
||
override EnterPhase → 额外过渡逻辑(动画/无敌帧/BD 子树切换)
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 Scene 节点结构
|
||
|
||
```
|
||
[Boss_XxxGuardian]
|
||
│ BossBase(具体 Boss 脚本,继承 BossBase)
|
||
│ ├── EnemyStats / EnemyMovement / EnemyCombat / EnemyFeedback
|
||
│ ├── BossSkillExecutor 接收 BD/Orchestrator 指令,执行 BossSkillSO 协程
|
||
│ ├── WeakPointSystem 弱点激活窗口管理(BossSkillExecutor 技能后开启)
|
||
│ ├── TelegraphSystem 攻击预兆提示(激光标线 / 范围高亮 / 地面警示)
|
||
│ ├── BehaviorTree 含 BD_EnterPhase 的行为树资产
|
||
│ └── AnimancerComponent
|
||
│
|
||
├── HurtBox 主体受击盒(Layer=EnemyHurtBox)
|
||
│
|
||
├── WeakPoint_Head 弱点受击盒
|
||
│ └── HurtBox(弱点专属,WeakPointSystem 控制激活/关闭)
|
||
│
|
||
├── HitBox_Slam 近战攻击 HitBox(Layer=EnemyHitBox)
|
||
├── HitBox_Sweep 横扫 HitBox(可与 BossSkillSO 绑定)
|
||
│
|
||
└── BossArenaBlocker(可选) 竞技场封锁触发器(Boss 战开始时封门)
|
||
```
|
||
|
||
---
|
||
|
||
### 4.3 技能执行流 BossSkillSO + BossSkillExecutor
|
||
|
||
```
|
||
BossSkillSO(CreateAssetMenu: BaseGames/Boss/BossSkill)
|
||
├── skillId / displayName
|
||
├── BossSkillType(枚举)
|
||
├── AttackPatternSO
|
||
│ ├── DamageSource(DamageSourceSO)
|
||
│ ├── KnockbackAngle
|
||
│ ├── 弹幕参数:ProjectilePrefab / Count / SpreadAngle / Speed
|
||
│ ├── AoE 参数:Radius / Offset
|
||
│ └── 时序:WindupDuration / ActiveDuration / RecoveryDuration
|
||
├── VulnerabilityWindowDuration 技能结束后弱点暴露时长(秒)
|
||
└── SkillSequenceSO(可选) 组合技序列(按顺序或随机排列多个 BossSkillSO)
|
||
|
||
BossSkillExecutor.ExecuteSkill(BossSkillSO)
|
||
│ if _isExecuting → return
|
||
│
|
||
└── StartCoroutine(ExecuteSkillCoroutine)
|
||
├── _onBossSkillStarted.Raise(BossSkillEvent)
|
||
├── TelegraphSystem.ShowTelegraph(skill.pattern) 预兆提示激活
|
||
├── WaitForSeconds(WindupDuration) 前摇等待
|
||
├── 激活 HitBox[] / ProjectileManager.Spawn(pattern) 伤害输出
|
||
├── WaitForSeconds(ActiveDuration) 活跃帧等待
|
||
├── 关闭 HitBox / 清理弹幕
|
||
├── WeakPointSystem.OpenWindow(VulnerabilityWindowDuration) 弱点窗口
|
||
├── WaitForSeconds(RecoveryDuration) 后摇等待
|
||
└── _onBossSkillEnded.Raise(BossSkillEvent)
|
||
|
||
WaitForSeconds 缓存:
|
||
static Dictionary<float, WaitForSeconds> _wfsCache
|
||
[RuntimeInitializeOnLoadMethod] ClearWFSCache()
|
||
→ 避免协程每次 new WaitForSeconds 的 GC 分配
|
||
```
|
||
|
||
**InterruptCurrentSkill()**:阶段切换时强制停止当前协程并调用 `FinishExecution()`,确保状态一致性。
|
||
|
||
---
|
||
|
||
### 4.4 阶段切换
|
||
|
||
```
|
||
BD_IsHPBelow(每帧轮询)
|
||
└── BossBase.IsHPBelow(ratio) = CurrentHP / MaxHP < ratio
|
||
→ true 时 BD 子树激活 BD_EnterPhase
|
||
|
||
BD_EnterPhase → BossBase.EnterPhase(phase)
|
||
├── _currentPhase = phase
|
||
├── BossPhaseEventChannelSO _onBossPhaseChanged.Raise(BossPhaseEvent{BossId, Phase})
|
||
│ → Boss HP 条分段动画(UI)
|
||
│ → 音乐系统切换 BGM 段落
|
||
│ → VFX 场景效果触发
|
||
└── [子类重写 EnterPhase]
|
||
├── BossSkillExecutor.InterruptCurrentSkill() 打断当前技能
|
||
├── 切换 BD 行为树活跃子树(换招式库)
|
||
├── 播放阶段过渡动画(Animancer)
|
||
└── 短暂无敌帧(保护阶段切换不被秒杀)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 共享战斗层 Combat Module
|
||
|
||
### 5.1 核心接口
|
||
|
||
| 接口 | 实现者 | 用途 |
|
||
|------|--------|------|
|
||
| `IDamageable` | `PlayerController` / `EnemyBase` | HurtBox 统一调用入口,解耦具体角色类型 |
|
||
| `IPoiseSource` | `PlayerController`(返回 None)/ `EnemyPoiseComponent` | 霸体等级声明,TakeDamage 中比较 |
|
||
| `IShieldable` | `ShieldComponent`(玩家专属) | 伤害先经护盾吸收,剩余量才走 TakeDamage |
|
||
| `IStatusEffectable` | `StatusEffectManager` | 状态效果施加入口,Combat 程序集不直接引用 StatusEffects |
|
||
| `IBreakable` | 可破坏机关 / 障碍物 | HitBox 命中非 HurtBox 对象时的分支处理 |
|
||
| `IPathAgent` | `EnemyNavAgent` | EnemyBase 通过接口引用导航,避免对 Navigation 程序集的直接依赖 |
|
||
|
||
---
|
||
|
||
### 5.2 HitBox → HurtBox 伤害流水线
|
||
|
||
```
|
||
HitBox.OnTriggerEnter2D(Collider2D other)
|
||
├── 1. Layer 白名单过滤(仅命中 EnemyHurtBox / PlayerHurtBox)
|
||
├── 2. _alreadyHit HashSet 防重复命中(同次激活期间)
|
||
├── 3. other.GetComponentInParent<HurtBox>() 获取受击盒
|
||
│
|
||
└── HurtBox.ReceiveDamage(DamageInfo)
|
||
├── 1. IsAlive 检查
|
||
├── 2. IDamageable.IsInvincible 检查
|
||
│ (冲刺无敌帧 / DeadState / Stats.InvincibleTimer)
|
||
├── 3. IShieldable.AbsorbDamage(amount)
|
||
│ 护盾优先吸收,返回穿透量
|
||
├── 4. IPoiseSource 霸体等级比较
|
||
│ DamageInfo.PoiseBreakLevel vs GetCurrentPoiseLevel()
|
||
├── 5. DamageInfo.FinalDamage 计算(基础 - Defense)
|
||
├── 6. IStatusEffectable.ApplyStatusEffect(DamageType)
|
||
│ (Fire → FireEffect / Poison → PoisonEffect)
|
||
├── 7. IDamageable.TakeDamage(info)
|
||
│ → PlayerController / EnemyBase 状态机转换
|
||
└── 8. HitConfirmedEventChannelSO.Raise(HitInfo)
|
||
→ HUD 命中提示 / 灵魂增加 / HitStop 触发
|
||
```
|
||
|
||
---
|
||
|
||
### 5.3 状态效果系统
|
||
|
||
```
|
||
StatusEffectManager(IStatusEffectable)
|
||
├── ApplyStatusEffect(DamageType type)
|
||
│ → 查找或创建对应 StatusEffect 实例并激活
|
||
│
|
||
├── FireEffect 持续 DoT(Tick 扣 HP)/ 视觉火焰 VFX
|
||
├── PoisonEffect 持续 DoT + 移动速度降低(可叠加层数)
|
||
└── StaggerEffect 触发 EnemyStaggerState / 破霸体
|
||
|
||
StatusEffectEventChannelSO 广播效果开始/结束(UI 状态图标)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 数据驱动 ScriptableObject 体系
|
||
|
||
| SO 类型 | 所属程序集 | 用途 |
|
||
|---------|-----------|------|
|
||
| `PlayerStatsSO` | `BaseGames.Player` | 玩家初始数值、最大值配置 |
|
||
| `PlayerMovementConfigSO` | `BaseGames.Player` | 移动速度/加速/跳跃力/冲刺参数等 |
|
||
| `PlayerAnimationConfigSO` | `BaseGames.Player` | 各状态动画 ClipTransition 集合 |
|
||
| `FormConfigSO` / `FormSO` | `BaseGames.Player` | 形态列表 + 各形态默认武器 |
|
||
| `WeaponSO` | `BaseGames.Player` | 武器连击动画/伤害来源/HitBox Prefab |
|
||
| `FormSkillSO` | `BaseGames.Skills` | 技能全量配置(动画/资源/效果/HitBox) |
|
||
| `CharmSO` / `EquipmentConfigSO` | `BaseGames.Equipment` | 护符效果列表 + Notch 容量初始值 |
|
||
| `DamageSourceSO` | `BaseGames.Combat` | 伤害值/类型/霸体破防等级/击退参数 |
|
||
| `ProjectileConfigSO` | `BaseGames.Combat` | 投射物速度/碰撞层/生命时长/弹幕参数 |
|
||
| `EnemyStatsSO` | `BaseGames.Enemies` | 敌人 HP/Defense/速度/攻击冷却 |
|
||
| `EnemyAnimationConfigSO` | `BaseGames.Enemies` | 敌人动画 Clip 集合 |
|
||
| `AttackPatternSO` | `BaseGames.Enemies`(Boss) | 攻击图案:伤害/弹幕/AoE/时序 |
|
||
| `BossSkillSO` | `BaseGames.Enemies`(Boss) | Boss 技能全量配置 |
|
||
| `SkillSequenceSO` | `BaseGames.Enemies`(Boss) | Boss 组合技序列(有序/随机) |
|
||
| `BossResourceConfigSO` | `BaseGames.Enemies`(Boss) | Boss 阶段资源(HP 阈值/技能池) |
|
||
|
||
**设计原则**:所有运行时组件在 `Awake` 中通过 `Initialize(SO)` 接收配置,与数据资产完全解耦,支持 Inspector 热替换和难度 A/B 测试,无需修改脚本代码。
|
||
|
||
---
|
||
|
||
## 7. 架构核心原则总结
|
||
|
||
| 原则 | 具体体现 |
|
||
|------|---------|
|
||
| **单一职责** | 移动 / 数值 / 战斗 / 动画各为独立 MonoBehaviour;`PlayerController` 仅负责 FSM 协调,不持有业务逻辑 |
|
||
| **事件驱动** | `EventChannelSO`(广播,跨程序集零直接引用)+ C# event(点对点,同程序集高频回调)双轨并行 |
|
||
| **数据与逻辑分离** | 所有配置数据存入 ScriptableObject;运行时组件只持有 SO 引用,数值修改在 SO 层完成 |
|
||
| **接口隔离** | `IDamageable / IPoiseSource / IShieldable / IStatusEffectable / IBreakable / IPathAgent` 六大接口隔离具体实现 |
|
||
| **状态不继承 MB** | `PlayerStateBase` 为 POCO 类,生命周期由 `PlayerController` 驱动,无 GC 开销 |
|
||
| **能力位图** | `AbilityType [Flags] uint` 支持任意组合查询,O(1) 位与运算,无枚举列表遍历 |
|
||
| **难度热切换** | `EnemyStats` / `PlayerStats` 均订阅 `DifficultyChangedEventChannel`,保持 HP 比例重算,运行时切换零重置 |
|
||
| **护符副作用隔离** | `ICharmEffect.OnEquip / OnUnequip` 配对调用,每个效果负责自身还原,`EquipmentManager` 不持有修改记录 |
|
||
| **GC 意识** | `WaitForSeconds` 协程缓存、`_alreadyHit HashSet` 复用、`SqrDistanceToPlayer`(避免 sqrt)、`BatchLOSSystem` 批量 Raycast |
|
||
| **执行顺序管控** | `PlayerMovement -200` → `PlayerController -100` → 其余默认 0,确保物理写入先于状态机读取 |
|