Files
zeling_v2/Docs_Dev/superpowers/specs/2026-07-21-enemy-ability-config-to-so-design.md
T

7.6 KiB
Raw Blame History

敌人能力配置迁移到 AbilitySO —— 设计文档

  • 日期:2026-07-21
  • 范围:把 8 个「在能力 MonoBehaviour 上直接 [SerializeField] 挂载」的能力的全部数值/资产参数(动画片段、时长、速度、次数、LayerMask 等)迁移到对应的 EnemyAbilitySO 子类 SO 中。场景对象组件引用保留在 MonoBehaviour。只改脚本 + 脚手架,不动现有 prefab / 资产(用户手动重生成替换)。

目标

  1. 能力的可配置参数统一放在 SO 里(数据与行为分离、跨实例复用、便于策划调参),消除「部分参数在 SO、部分在脚本」的分裂。
  2. 每个需要迁移的能力类型有一个专属 EnemyAbilitySO 子类,类型安全、字段自解释、编辑器可见。
  3. 迁移边界清晰:数值/LayerMask/Clip/资产 SO → 子类 SO场景对象组件引用(BodyContactDamage/HitBox/HurtBox)→ 保留在 MonoBehaviour(逐实例场景引用无法进共享 SO 资产)。

背景(现状)

  • EnemyAbilitySOAssets/_Game/Scripts/Enemies/Abilities/EnemyAbilitySO.cs)是能力配置基类,承载通用配置:abilityIdattackSequencecooldown、telegraph、中断规则、调度提示、exclusionGrouppriority
  • EnemyAbilityBaseMonoBehaviour 抽象基类)持有 [SerializeField] protected EnemyAbilitySO _config,生命周期/冷却/中断在基类。
  • EnemyAttackSO.clipClipTransition)已在 SO 层,供 attackSequence 型能力(Melee/Charge/Blink/Projectile/Leap/ChaoFeng 等)使用——这类能力已是 SO 驱动,不在本次范围
  • 有 8 个能力在 MonoBehaviour 上直接挂参数(含 ClipTransition 及其它数值),是本次迁移对象。
  • 现有 17 个 ABL_*.asset 配置资产均为基类 EnemyAbilitySO 类型;片段目前挂在各 prefab 的能力组件实例上。

设计

A. 八个子类 SO

在新子目录 Assets/_Game/Scripts/Enemies/Abilities/Configs/ 下,为每个能力建一个 XxxAbilitySO : EnemyAbilitySO,各带 [CreateAssetMenu(menuName = "BaseGames/Enemies/Abilities/<名>", fileName = "ABL_")]。字段迁移如下(以脚本实际字段为准,实现时逐文件核对;下表为已核实的字段):

能力 MonoBehaviour 子类 SO → 迁入 SO 的字段 保留在 MonoBehaviour(场景引用)
ContactChaseAbility ContactChaseAbilitySO startClip, loopClip, endClipClipTransition);dashSpeed(float) BodyContactDamage _contactDamage
RepeatSlamAbility RepeatSlamAbilitySO startClip, loopClip, endCliphitActiveTime, staggerDuration(float)slamCount(int) HitBox _hitBox
CeilingHangStrikeAbility CeilingHangStrikeAbilitySO strikeClip, loopClip, endCliphangDuration(float) HitBox _attackHitBox, HurtBox _hurtBox
AnimatedCeilingDropAbility AnimatedCeilingDropAbilitySO fallLoopClipfallGravityScale, maxFallTime, recoveryTime(float)groundMask(LayerMask) BodyContactDamage _contactDamage
AppearAbility AppearAbilitySO appearClip
FacePlayerAbility FacePlayerAbilitySO faceClip
MeleeVulnerabilityAbility MeleeVulnerabilityAbilitySO attackClip;打击归一化时机字段;staggerDuration(float) HitBox _hitBox, HurtBox _hurtBox
PlayClipAbility PlayClipAbilitySO clip
  • 字段名去掉下划线前缀(SO 公有字段风格,对齐 EnemyAbilitySO/EnemyAttackSO 现有公有字段),保留原 [Header]/[Tooltip]/[Min]/[Range] 语义。
  • 子类只加自己的字段,通用配置继续由基类承载。

B. 基类:类型化配置解析(根因显式报错,无兜底)

EnemyAbilityBase 增加受保护助手:

/// <summary>把 _config 解析为期望的子类型;类型不符时显式报错(不回退)。</summary>
protected T ResolveConfig<T>() where T : EnemyAbilitySO
{
    if (_config is T typed) return typed;
    Debug.LogError($"[{GetType().Name}] _config 需为 {typeof(T).Name}" +
                   $"实际 = {(_config != null ? _config.GetType().Name : "null")}。请重建为正确的子类 SO。", this);
    return null;
}
  • 类型不符或漏配时显式报错(符合 CLAUDE.md §6 根因修复、禁止下游兜底),不静默回退到默认值。
  • 不引入泛型基类(EnemyAbilityBase<T>),避免波及 attackSequence 型能力与 Unity 序列化面。基类保持非泛型,子类各自缓存类型化配置。

C. 每个能力 MonoBehaviour 的改动(以 ContactChase 为例)

private ContactChaseAbilitySO _cfg;

protected override void Awake()
{
    base.Awake();
    _cfg = ResolveConfig<ContactChaseAbilitySO>();
}
  • 删除迁走的 [SerializeField] 字段(_startClip/_loopClip/_endClip/_dashSpeed)。
  • 使用处:_startClip_cfg.startClip_dashSpeed_cfg.dashSpeed,其余同理。空片段判空逻辑不变(_cfg.startClip.Clip != null)。
  • _cfg == null(漏配/类型错),执行路径应安全短路(ExecuteCoroutine 起始判 _cfg == nullyield break),错误已由 ResolveConfig 报出——不静默补默认值。
  • 场景引用字段(_contactDamage 等)保留不动。

D. 脚手架 / 创建入口

  • 8 个子类各自 [CreateAssetMenu]:用户可从菜单创建正确类型的 ABL_ 资产。
  • CharacterWizardWindow / DataHubWindow 有创建能力 SO 的入口,改为按能力类型创建对应子类(实现前先核对这两个入口现状;无则仅靠 CreateAssetMenu)。
  • SceneObjectPlacerToolAssignAsset(ability, "_config", …, "ABL_xxx") 按资产名引用——用户重建的 ABL_ 资产为新子类即可正确绑定,脚手架代码基本不变(如需,补充「资产类型应为子类」的自检提示)。

E. 现有资产迁移

  • 按用户选择:代码 + 脚手架保证正确,用户手动重建这 8 类相关的 ABL_ 资产(旧资产是基类 EnemyAbilitySO,重建为子类并把参数填进 SO),并重生成对应 prefab。
  • attackSequence 型能力(ChaoFeng/Melee/Charge/Blink/Projectile/Leap 等)继续用基类 EnemyAbilitySO,不受影响。

影响文件

  • 新增:Assets/_Game/Scripts/Enemies/Abilities/Configs/ 下 8 个子类 SO 脚本。
  • 修改:EnemyAbilityBase.cs(加 ResolveConfig<T>)。
  • 修改:8 个能力 MonoBehaviour(删字段、Awake 解析、使用处改读 SO)。
  • 可能修改:CharacterWizardWindow.cs / DataHubWindow.cs(能力 SO 创建入口,按现状定)。
  • 不改:EnemyAbilitySO.cs(基类不动,除非需要把某几个当前 protected 成员对子类可见——实现时确认 _config 已 protected,子类无需访问基类私有)。

验证

  • 编译门 0 错误。
  • EditMode 测试:
    • ResolveConfig<T> 类型匹配返回实例;类型不符/为 null 时报错(LogAssert.Expect(LogType.Error, ...) 断言)。
    • 每个子类 SO 可 CreateInstance 且暴露预期字段(反射校验字段名/类型存在)。
  • MCP 放置验证:在活动场景放置一个能力对象、绑定对应子类 SO 实例,反射读取能力的 _cfg 字段确认非空且参数值来自 SO(不必真跑 Animancer)。
  • 自检工具:Validate All ScriptableObjects 无新增错误。

非目标

  • 不迁移场景对象组件引用(BodyContactDamage/HitBox/HurtBox)——保留在 MonoBehaviour 逐实例绑定。
  • 不动 EnemyAttackSO / attackSequence(其 clip 已在 SO 层)。
  • 不引入泛型能力基类。
  • 不改现有 prefab / 资产(用户手动重生成)。