# 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() 注入 │ ├── [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` 状态字典,每帧驱动 `_currentState` 的 `OnStateUpdate / OnStateFixedUpdate`,并在 `TransitionTo()` 时依次调用 `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 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 _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.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,确保物理写入先于状态机读取 |