Files
zeling_v2/Docs_Dev/superpowers/specs/2026-07-30-boss-ai-single-track-design.md
T
joywayer b0fd040904 docs(enemy): 按 Task 1+2 审查结论修订 spec 与计划
spec:ResourceFull 由「无组件时恒 false」改为显式抛,与 Boss facet、AnchorAt
统一为「依赖组件缺失一律抛,不返默认值」。
计划:Task 16 补上 BossBase 残余三处行为树残留的清理项(含运行时告警字符串);
Task 19 记录 Patterns/ 是零外部引用的独立程序集,可整目录删。
2026-07-30 12:32:43 +08:00

37 KiB
Raw Blame History

Boss AI 双轨统一:决策层与执行层一并归并到小怪轨

日期:2026-07-30  状态:设计已确认,待实施 背景:小怪走 EnemyAiBrainBrainGraph+ 组合式模块 + EnemyAbilityBase/EnemyAbilitySO Boss 走 BossBase + BossSkillExecutor + BossSkillSO。2026-07-27 的抽取决策记录把终态定为 「决策层统一 BrainGraph + 执行层按复杂度分层(Boss 保留 BossSkillExecutor 富编排)」。 本次经竞品调研与代码现状核查,推翻其中"执行层分层"那一半Boss 侧那层富编排从未真正存在。


1. 结论摘要

决策 内容
决策层单轨 Boss 走 BrainGraph。每个 Boss 一个 AiScript 定制类(已有的约 5% 定制路径),不建 Boss 骨架、不建 Boss 配方
执行层单轨 Boss 招走 EnemyAbilitySO + EnemyAttackSO + EnemyAbilityBase。招式编排权威 = 动画时间轴(clip + 归一化时机 + 动画事件)
Boss 专属不是"另一条轨" 而是旁挂 MonoBehaviour(浮空/击落/资源)+ 一个 IBossControl facet(阶段)
阶段 = 换招池 BossPhaseAbilityGate 按阶段启用/禁用能力组件。不在 SO 上加阶段字段
选招策略是可换的小构件 AttackSelectionMode 加第三个值(加权随机 + 防重复)。不抽策略接口,enum 就是接缝
旧 Boss 轨整包退役 9 个脚本 + 5 个资产删除,判据是「有更优替代才删」
脚手架一并改 CharacterWizardWindowSceneObjectPlacerTool.PlaceChaoFeng 是旧轨资产的创建链路,不改则会持续产出旧轨对象(CLAUDE.md 第 2、6 条)

核心原则:决策归图,编排归动画,能不能用归招式自己,选哪个归选招器,演出归旁挂组件。


2. 竞品证据

调研对象为同类型(横版平台动作 / Metroidvania)代表作及其续作的 Boss 设计,2026-07-30 完成。 以下六条是本设计的实证依据。

2.1 技术轨本来就是单轨。 代表作中所有敌人与 Boss 一律使用同一套可视化状态机(每个 Boss 一张 名为 Control 的图),与小怪用的是同一技术栈。差别只在状态数量,不在架构。 → 双轨没有技术必要性。

2.2 Boss 决策层极简,复杂度全在单招内部。 招数量:某作最终 Boss 9 招,另几个知名 Boss 分别 6 招、4 招、3 招。决策形状统一是「选招 hub 态 → 加权随机挑一招(带防重复与位置门)→ 打完回 hub」。 → Boss 决策层不需要比现有 ApproachAttackEngagement 复杂。

2.3 阶段 = 换招池 + 一段过渡演出。 某作最终 Boss 四阶段:P1 三招;血量阈值 1 两招并提速; 阈值 2 减掉两招换成新招;P4 只剩两招。过渡是固定的「站定 → 仰头咆哮 → 硬直玩家」。 → 阶段的本质是招池过滤器 + 一段无敌演出,现有 BeginPhaseTransition 已是正确形态。

2.4 续作相对前作唯一的 Boss AI 改动,是选招谓词而非架构。 开发者访谈明确说明:前作 Boss 是 反应式的——按玩家站位选招;续作去掉了这一点,改为主动式——按自身计划推进,不看玩家在哪。 → 这条最有价值:它说明「选招策略」应当是一个可替换的小构件,而不是一整套 AI 技术栈。 现有 AttackSelectionMode 只有 Priority / WeightedRandom 两维,缺的正是「读不读玩家位置」这一维。

2.5 Boss 没有未发现层。 竞品 Boss 不巡逻、不伪装、不警觉,靠竞技场进入 / 锁门 / 触发器开战。 → 小怪骨架的第一层对 Boss 完全无用;Boss 要的是入场演出层。这是不复用 PerceptionSkeleton 的理由。

2.6 committed 起手是共识。 预警 → 起手 → 打完,不中途收招(某作的空中俯冲锁定的是起手瞬间的 玩家位置,而非实时追踪)。 → 与 2026-07-29 组合式模块设计 §3.6 已定的「攻击起手后打完」一致,两轨在这点本来就同构。


3. 代码现状核查

3.1 Boss 现在没有决策层

UseBossSkillWeighted 零调用者(原行为树任务已移除)。ENM_ChaoFeng.prefab没有 EnemyAiBrain(无 _recipe / _definitionId 序列化字段)。嘲风目前打不起来。

这条推翻了 2026-07-27 决策记录 §5 的执行建议「不要拿已能跑的 ChaoFeng 开刀验证」—— 它不能跑,因此没有回归风险,正是首个验证对象。

3.2 Boss 的"富执行层"是空架构

  • 全项目 0 个 AttackPatternSO 资产、0 个 SkillSequenceSO 资产。
  • 5 个 ABL_ChaoFeng_*.asset(实为 BossSkillSO)除 skillIdweight 外全空: attackPatterns: []sequenceOnMiss: {fileID: 0}skillAnimation._Clip: {fileID: 0}vulnerabilityWindows: []counterResponses: []cooldown: 0
  • 因此 BossSkillExecutor.ExecuteSkillCoroutine 跑一遍是纯空转:无动画、无序列、无判定。

3.3 零运行时消费者清单

成员 状态
BossSkillSO.attackPatterns 仅被两个编辑器窗口读取,运行时零读取
interactionTags / buildsRage / poiseWindowBossSkillSO 上那份) 零读取
PlayerCounterResponse.soulPowerGrant / spiritPowerGrant 零读取(ExecuteCounterEffect 未读)
ArenaEventType/Params/Trigger/DataIArenaInteractable 零消费者
TelegraphSystem 零消费者(调用方 BD_TelegraphAttack 已不存在)
WeakPointSystem.GetDamageMultiplier() 零调用者——注释称"由 BossStats 调用",项目无 BossStats 类型。弱点伤害倍率从未生效
BossSkillEventChannelSO BossSkillExecutor 在发,全项目零订阅方
EnemyBase.ConsumeParryEvent 零调用者(BD_OnParried 已不存在)
EnemyBase.ReceiveParry 零调用者(形态正确但未接线,见 §6.2)

3.4 嘲风预制体实况

挂载的 Boss 组件只有三个:BossSkillExecutor5 个空技能)、ChaoFengFloatControllerChaoFengKnockdownCounter未挂 WeakPointSystemBossResourceTelegraphSystemEnemyAiBrain

而嘲风实际的招式编排走的是动画事件clip 上的 SpawnProjectile 事件 → ChaoFengBoss.SpawnProjectile(payload)), 即小怪轨 EnemyAttackSO 的做法。唯一的 Boss 用脚投票选了另一条路。

3.5 现存弹反反制路径有 bug

BossBase.HandleParrySuccess 订阅的是 ParryInfoEventChannelSO 这个全局弹反成功频道, 无来源过滤。玩家弹反一只小怪也会让场上的 Boss 进入硬直。这是应当删除而非保留的另一个理由。


4. 架构:关注点归属

关注点 归属 依据
选状态 / 何时出手 / 何时换阶段 AI 图(每 Boss 一个 AiScript 这些是决策
一招怎么打(clip + 归一化时机 + HitBox + 弹体) EnemyAbilityBase 子类 + EnemyAbilitySO 与小怪同构
这招现在能不能用(阶段门) 能力组件的启用状态(BossPhaseAbilityGate 阶段=换招池在数据上显式(§2.3
选哪一招(权重 / 防重复) EnemyAttackSelector 已是唯一选招器
阶段过渡无敌演出 BossBase.BeginPhaseTransition 已实现且正确,保留
死亡 Die / PerformDeath(物理层) 与小怪同一结论;Boss 已在走这条
浮空 / 击落计数 / 资源 旁挂 MonoBehaviourAI 图不知道其内部 单 Boss 或专项机制,不上升到骨架

4.1 为什么不建 Boss 骨架

竞品每个 Boss 都是一张手写图(§2.1)。Boss 数量在十几个量级,配方化省下的编译与复制成本极小, 而完全自由的价值很高。更关键的是:Boss 之间的差异远大于小怪(浮空 / 击落计数 / 多阶段竞技场 / 守卫箱),骨架会迅速退化成开关面板——正是 2026-07-29 刚从 PerceptionStateMachine.Config 上修掉的病。

复用 PerceptionSkeleton 也被否决:它专为感知升降级而存在,会给 Boss 挂上用不到的 Alert 态、 InVision+HasAlert 死边和 leftVision → Rest 脱战边(§2.5:Boss 不脱战)。

统一的是运行时(BrainGraph + AiRuntime + IsControllable 让位门)与建态原语(AiStateFragments), 不是图的形状。

4.2 共享图片段(不是可插拔模块)

Boss 图手写,但重复形状抽成静态片段——AiStateFragments 那个级别,不需要 [SerializeReference] 下拉、不需要 SO

public static class BossFragments
{
    /// 阶段过渡态:OnEnter 调 BeginPhaseTransition,过渡结束后转出。
    public static BrainBuilder.StateBuilder PhaseTransition(
        BrainBuilder b, string state, int targetPhase, float invincibleDuration);

    /// 逼近 ↔ 选招攻击。转发到 ApproachAttackEngagement 提取出的静态建态方法,
    /// 使交战模块与 Boss 图共用同一份实现(态名可指定,Boss 图可有多组)。
    public static BrainBuilder.StateBuilder ApproachAttack(
        BrainBuilder b, string approach, string attack, string rest);

    /// 移动到第 index 个竞技场锚点(BossArenaAnchors),到位后转出。
    public static BrainBuilder.StateBuilder MoveToAnchor(
        BrainBuilder b, string state, int index);
}

ApproachAttackEngagement.Build 的建态逻辑提升为 internal static,模块与 BossFragments 各自转发。 入场直接用已有的 AiStateFragments.Ability(b, Intro, introAbilityId)

4.3 嘲风 AI 图形状(范例)

[AiDefinition("ChaoFeng")]
public sealed class ChaoFengAi : AiScript
{
    protected override void Build(BrainBuilder b)
    {
        b.Entry(Wait);

        // 竞技场触发前静置(态名常量声明略)
        AiStateFragments.Locomotion(b, Wait, LocomotionMode.Idle)
            .To(Intro).OnEvent(AiSignal.Engaged);

        // 入场演出
        AiStateFragments.Ability(b, Intro, "chaofeng_intro")
            .To(Ground).When(x => !x.Combat.IsAbilityRunning("chaofeng_intro"), "introDone");

        // 阶段 0:地面,逼近 ↔ 选招(四招由阶段门放行)
        BossFragments.ApproachAttack(b, Ground, GroundAttack, rest: Ground)
            .To(PhaseTx).When(x => x.Vitals.HpBelow(0.5f), "hp<50%");

        // 阶段过渡:无敌 + 浮空演出(ChaoFengBoss.OnBeginPhaseTransition 已实现)
        BossFragments.PhaseTransition(b, PhaseTx, targetPhase: 1, invincibleDuration: 2f)
            .To(Air).When(x => !x.Boss.IsPhaseTransitioning, "txDone");

        // 阶段 1:空中,悬停 ↔ 风石(地面四招已被阶段门禁用)
        AiStateFragments.Locomotion(b, Air, LocomotionMode.Face)
            .To(AirAttack).When(x => x.Combat.HasEligibleAttack(), "attackInRange");
        b.DeclareState(AirAttack)
            .OnEnter(x => x.Combat.UseBestAttack())
            .To(Air).When(x => !x.Combat.IsAbilityRunning(), "attackDone");
    }
}

死亡不在图上:ChaoFengBoss.Die() 的击败演出协程照旧,NotifyDecisionStop()(原 StopBehaviorTreeAiSignal.Died 让全局死亡边把决策停住。与 2026-07-29 §3 修订的结论一致——死亡不是一个决策


5. 新增的五件

# 内容 规模
1 IBossControl facet + IAiContext.Boss 小接口
2 BossPhaseAbilityGate 组件 小组件
3 AttackSelectionMode.WeightedRandomAntiRepeat + 选招器防重复 改两个文件
4 EnemyAnimationEvents 补 4 个 case + 两个子系统引用字段 各 23 行
5 BossArenaAnchors 组件 + 「移动到第 N 锚点」图片段 小组件

修订(2026-07-30,实施计划阶段):初稿列的第 5 件「EnemyBase.SetInvincible(float)已取消。 核查 PlayerAnimationEvents 后确认玩家侧的 EnableIFrame / DisableIFrame 走的是 HurtBox.SetInvincible(bool)——该 API 已存在,无敌时长由动画时间轴上两个事件的间距表达。 敌人侧照同一形态接线即可,不需要在 EnemyBase 上新造带时长的无敌源。 这也更正确:时长归动画,不归代码常量。

5.1 IBossControl

namespace BaseGames.AI
{
    /// Boss 专属决策面。小怪图访问 IAiContext.Boss 会抛异常(显式报错,不静默兜底)。
    public interface IBossControl
    {
        int   CurrentPhase          { get; }
        bool  IsPhaseTransitioning  { get; }
        bool  ResourceFull          { get; }   // BossResource 满值;未挂该组件即抛(见下)
        void  BeginPhaseTransition(int targetPhase, float invincibleDuration);

        // 竞技场锚点(§5.5)。归本 facet 而非黑板:见下方修订说明。
        Vector2 AnchorAt(int index);
        float   DistanceToAnchor(int index);
    }
}

修订(2026-07-30,实施计划阶段):锚点坐标初稿设计为经 IAiContext.Blackboard 传递 BossBaseAwake 写入黑板键)。该方案有两处硬阻塞,已废弃:

  1. 拿不到黑板 —— EnemyAiBrain._context 是私有字段且无公开访问器,BossBase 无从写入。
  2. 时序坑 —— EnemyBrainContext.ResetScratch()_blackboard.Clear()(对象池复用时调用), 写入点必须排在它之后,是个易错的隐式顺序依赖。

改为挂在 IBossControl 上:锚点本就是 Boss 专属知识,facet 已存在,BossBaseAwake 解析组件即可。净收益是少一个失败模式(黑板键缺失)、少一条隐式时序约束,且 DistanceToAnchor 把"我离锚点多远"封在 Boss 内部,不需要给 AI 层引入新的位置概念。

EnemyBrainContext.Boss => _boss ?? throw new InvalidOperationException(...)。 按 CLAUDE.md 第 6 条:小怪图误用它必须崩,不能返回一个空对象把问题盖住。

修订(2026-07-30Task 1+2 代码审查):ResourceFull 初稿定为「无资源组件时恒 false」, 已改为未挂 BossResource 时显式抛。原设计是同一条第 6 条禁止的下游兜底—— 图上挂了 When(x => x.Boss.ResourceFull) 边、预制体却漏挂组件时,那条边会永远不成立且零报错。 与紧邻的 Boss facet、以及 §5.5 的 AnchorAt 保持同一失败语义:Boss 专属 facet 的每个成员, 在其依赖组件缺失时一律显式抛,不返回默认值。

BossBase 实现 IBossControlEnemyBrainContext 在构造时 _boss = enemy as BossBase

5.2 BossPhaseAbilityGate

[Serializable] struct PhaseEntry { public EnemyAbilityBase ability; public int[] phases; }

BossBase.EnterPhase(n) 调用本组件按表启停能力组件;OnSpawn 重置到阶段 0 的启用集 (对象池复用)。同时 EnemyAbilityBase.CanUse&& enabled——现状下禁用的组件 CanUse 仍为真,选招器会选中一个 StartCoroutine 必然失败的招。

为什么阶段门不放 SO:阶段可用性是跨所有 Boss 招的共性,而具体招式已经在用 EnemyAbilitySO 的类型化子类(RushAbilitySO / RepeatSlamAbilitySO …)。若做成 BossAbilitySO : EnemyAbilitySO,Boss 的近战招就要同时继承 Boss 与 Melee 两个子类—— C# 单继承直接堵死。

5.3 WeightedRandomAntiRepeat

选招器持有 _lastPicked,对上一招施加权重系数(默认 0.3,放 EnemyStatsSO)。 BossBase.UseBossSkillWeighted 的同名逻辑就此并入选招器后删除。

为什么不抽 IAttackSelectionStrategy:按 2026-07-27 §Layer B/C 的判据——三个 enum 值互不耦合、 Select 是一个三目、每模式一个 private 方法,不存在"每加一种就长一根 if 分支"的结构。 等真要做 §2.4 那种主动计划式选招时再抽,那时才有第 4、5 个消费者。enum 就是留给它的接缝。

5.4 动画事件补接(四个 case

AnimationEventType 有 20 个值,EnemyAnimationEvents.HandleEvent 只接了 7 个 EnableHitBox / DisableHitBox / SpawnProjectile / RoarStart / RoarEnd / PhaseTwoStart / AnimationComplete)。玩家侧 PlayerAnimationEvents 接得更全。 敌人侧漏掉的这四个恰好都是 Boss 复刻要用的:

补接 复刻的竞品能力
PlaySFX / TriggerFeedback 音效预警——竞品有 Boss 用两句语音区分物理招与远程招,预警的是招式类别而非具体招式,让玩家缩小可能性但不能确定。这是最经济的 telegraph 手法,现在写不出来
EnableIFrame / DisableIFrame 招式中途无敌:突进穿过玩家时不吃伤害、传送消失期间无敌

四个 case 的实现与 PlayerAnimationEvents 逐字对称:反馈两件走 IFeedbackPlayer.TriggerPreset / PlaySFXByIdEnemyFeedback 已实现该接口),无敌两件走 HurtBox.SetInvincible(bool)API 已存在)。 EnemyAnimationEvents 因此需补两个子系统引用:HurtBox _hurtBoxIFeedbackPlayer _feedback (后者在 AwakeGetComponentInParent<IFeedbackPlayer>() ?? NullFeedbackPlayer.Instance 解析, 与玩家侧同写法)。

5.5 BossArenaAnchors

竞技场锚点走位(站在悬空平台上出招、传送到房间固定角落)是竞品定点型 Boss 的核心。 IEnemyLocomotion.MoveTo(Vector2) 能到点,但锚点集合无处安放。 一个持有 Transform[] 的组件 + 一个「移动到第 N 个锚点」的图片段即可。

坐标经 IBossControl.AnchorAt(int) / DistanceToAnchor(int) 暴露给图(不走黑板,见 §5.1 修订)。 锚点物体放在场景里而非 SO 里——它随房间布局走。下标越界或引用为空显式抛, 不回退到 Boss 自身位置(那会让"锚点漏配"表现为"Boss 站着不动",是典型的下游兜底掩盖问题)。


6. 退役清单

判据:有更优替代才删。 按替代的成熟度分四类。

6.1 A 类:有现成更优替代 → 直接删

删除 更优替代(已存在)
BossSkillSO EnemyAbilitySO + EnemyAttackSO(归一化时机、槽位 HitBox、ProjectileConfigSO
AttackPatternSO EnemyAttackSOAoERadius/AoEOffset 的更优形态是 HitBox 碰撞体几何;KnockbackAngleDamageSourceSO.KnockbackForce + 命中方向
SkillSequenceSO EnemyAbilitySO.attackSequence(顺序连段)+ RepeatSlamAbility(范围内重复)
BossSkillExecutor EnemyAbilityBase 子类 + EnemyAttackSelector
InteractionTag DamageFlags——CanBeParriedHurtBox.cs:77 已生效,"不可弹反招"今天就能配
BossSkillSO.poiseWindow EnemyAttackSO.hasPoiseWindow/poiseLevel/poiseStartT/poiseEndT
ArenaEventType/Params/Trigger/DataIArenaInteractable EnemySpawnerOnEvent(动画事件生成 hazard)。BossSkillEventChannelSO 零订阅方,删执行器不丢现有功能;若将来场景机关要按招响应,接缝是在能力层发同一频道
BossSkillCategory / BossSkillType AbilityCategory
TelegraphSystem + EnemyAbilitySO.telegraphVfxKey/telegraphDuration + EnemyAbilityBase.TelegraphRoutine clip 姿态 + 动画事件(§5.4 补接后)。三者是同一件事的三条平行路,且"生成 VFX 然后干等 N 秒"会在动画前插一段无动画静止
BossBase.UseBossSkill / UseBossSkillWeighted / LastUsedSkillId / IsSkillAvailableInPhase / CheckResourceCost / 三个缓冲区 EnemyAttackSelector + WeightedRandomAntiRepeat + BossPhaseAbilityGate
BossResourceCost / autoTriggerOnFull / fullTriggerSkill / resetValueAfterTrigger AI 图条件边。"资源满自动放招"由 BossResource 直接调 UseBossSkill绕过决策层,违反"AI 只决策、能力负责实现";正确形态是图上一条 When(x => x.Boss.ResourceFull) 边进专属招态
EnemyBase.ConsumeParryEvent + _wasParried / _parryTimestamp / ParryEventTTL 零调用者;ForceState(Stagger) + IsControllable 让位门是更优表达
Editor/Modules/BossSkillModule.csEditor/Enemies/BossSkillSequenceWindow.cs 依附 BossSkillSO,类型删除后必然失效。BossSkillModule 实现 IDataModule 且无显式注册点(反射发现),删文件即可
5 个 ABL_ChaoFeng_*.asset BossSkillSO。注:ABL_ 前缀本身合规AssetFolderSpec.md 第 298 行),删除原因是内容为空

6.2 B 类:替代需要顺手造,造完更优 → 删 + 造

这三项现成的更优替代并不存在,是本设计建议顺手造一个。

WeakPointSystem → 倍率下沉到 HurtBox HurtBox 没有伤害倍率字段,所以"打特定部位加伤"目前无载体。但 WeakPointSystem 的实现是坏的: 倍率写进自己的私有字段,GetDamageMultiplier() 零调用者,注释里的 BossStats 类型不存在。 更优形态是倍率归 HurtBox 自己(一个字段 + 伤害计算处一次乘法,约 3 行),弱点的定时开关由能力控制—— MeleeVulnerabilityAbility 已经证明「攻击后开放脆弱窗口」这个形态可行。

PlayerCounterResponse / CounterType / BossBase.ApplyCounterResponse / ExecuteCounterEffect / CounterStaggerCoroutine / _onParrySuccessEnemyBase.ReceiveParry ReceiveParry(staggerDuration) 已存在且形态正确(强制 Stagger + 打断全部能力 + 定时恢复,小怪 Boss 通用,不需要按 skillId 查表),但零调用者。删除现路径同时修掉 §3.5 的全局误伤 bug。

代价须明示DamageInfo没有攻击者引用(只有 SourceProjectile),所以"谁被弹反谁硬直" 这根线要在 Combat 层补——要么 DamageInfo 加 attacker,要么弹反成功时回调发起攻击的 HitBox列为独立后续任务,本次不做。 期间 Boss 被弹反不会硬直,但优于现在的误伤行为。

BossSkillSO.designNoteEnemyAbilitySO.designNote 无替代(EnemyAttackSO.attackName 只是调试名)。目标体量下 150+ 能力需要设计备注,加一个 [TextArea] 字段。

6.3 C 类:无替代 → 保留并改造

保留 改造
BossResource + BossResourceConfigSO 项目无第二套敌人资源条,"蓄能/怒气"是真机制。删掉自动触发三字段(见 A 类),保留数值维护 + NormalizedValue,新增 IsFull,触发权交回 AI 图(经 IBossControl.ResourceFull
EnemyBase.ReceiveParry 形态正确,等 Combat 层接线(§6.2)
EnemyBase.StopBehaviorTree 改名 NotifyDecisionStop()(行为树债清理),同步改 EnemyDeathSequenceChaoFengBoss 两处调用点
ChaoFengFloatController / ChaoFengKnockdownCounter 单 Boss 专属机制,形态正确,不动
BossBase.BeginPhaseTransition / EnterPhase / IsPhaseTransitioning / IsInvincible 覆写 已实现且正确,仅新增 IBossControl 实现

6.4 D 类:会丢一个编辑器视图

删除 BossSkillModule / BossSkillSequenceWindow 后,能力资产没有任何编辑器总览视图 EnemyModule 不涉及能力资产,已核)。列为后续待补:EnemyAbilityModule(能力总览 + 射程 / 权重 / 冷却 / 阶段一览)。不阻塞本次——AiDefinitionValidator 那条校验线才是防 450+ 引用出错的关键,优先级更高。

6.5 明确不做的四件

不做 理由
Boss 骨架 / Boss 配方 SO §4.1
IAttackSelectionStrategy 策略接口 §5.3YAGNI,留 enum 接缝
主动计划式选招 §2.4 是方向不是需求。等真要"不看玩家站位、按自身轮转"时加第 4 个 enum 值
多体 Boss 出招令牌 见 §7.2。等真设计双体 Boss 时再加

7. 表达力核对:能否复刻竞品 Boss

7.1 能直接表达(现有构件已覆盖)

竞品行为 项目对应构件
阶段加招 / 减招 BossPhaseAbilityGate
阶段过渡定格咆哮 + 硬直玩家 BeginPhaseTransition(无敌)+ RoarStart/RoarEnd 动画事件(已接线)
加权随机选招 + 防重复 EnemyAttackSelector + WeightedRandomAntiRepeat
按玩家距离 / 站位选招(反应式) 招式自管圆形射程 InAttackRange() + preferredMinRange/MaxRange
起手锁定玩家位置的落点攻击 嘲风 tornado_large 已实现(生成瞬间取玩家位置)
不追踪的固定弧线弹幕(空间封锁) projectileCount + spreadAngleDeg + projectileFireT
突进穿越场地 RushAbility / ChargeAbility / MultiDashAbility
跳跃砸地 LeapAttackAbility
传送到玩家侧后突袭 BlinkStrikeAbility
天花板悬挂 / 掉落突袭 CeilingDropAbility / CeilingHangStrikeAbility
玩家还在范围内就反复砸 RepeatSlamAbility
召唤小怪 EnemySpawnerOnEvent(动画事件驱动,零代码)
招式霸体不被打断 interruptOnHurt=false + EnemyPoiseComponent
起手后打完不收招 committed 攻击(Attack 态不挂脱战边)
不可弹反招(必须闪避) 该招 DamageSourceSO.Flags 去掉 CanBeParriedHurtBox.cs:77 已在判定
入场演出 AppearAbility + AiSignal.Engaged(新增该枚举值)
击落 / 破防计数 ChaoFengKnockdownCounter
浮空 / 飞行阶段 FlyingNavigator + ChaoFengFloatController

最后那条顺带证实:InteractionTag.Parryable / Unblockable 与 Combat 层的 DamageFlags同一件事两处表达,删掉不丢功能,反而消除打架隐患。

7.2 需要新组件的一处:多体 Boss 出招令牌

竞品有 Boss 在某阶段以两个实体同时行动且交替出招(一只出招时另一只等待,不会同时放同一招)。 项目 AI 图是每敌人独立,Blackboard 是 per-contextEnemyBrainContextnew Blackboard()), 无跨敌人通道。

这不是架构缺口:形态是一个 BossEncounterCoordinator 持有出招令牌,参战 Boss 的选招多一个 「我持有令牌吗」的门。加一个组件 + CanUse 上一个门,不推翻本设计任何决策。 现在不做,等真设计双体 Boss 时再加。

7.3 两处看着像缺口、其实不是

命中才追加连段。 BossSkillSO.sequenceOnHit 是整个 Boss SO 里唯一有真实语义却要被删的字段。 但竞品罕见(连段是固定的,不看是否命中;更常见的是"玩家还在范围内就重复",RepeatSlamAbility 已覆盖)。 真要的话形态是一个能力子类——HitBox.OnHitConfirmed 已存在,能力自己判断再决定跑不跑第二段。 不需要一整套序列 SO。

竞技场机关联动。 arenaEvents / IArenaInteractable 只是一张零消费者的表。替代路径两条且都已存在: 招式动画上挂 SpawnProjectile 生成 hazard,或场景侧订阅招式事件频道。


8. 脚手架修改(CLAUDE.md 第 2、6 条)

旧轨资产有两条创建链路,不改则会持续产出旧轨对象——这是根因,必须与代码一并修。

8.1 Editor/Character/CharacterWizardWindow.cs

位置 现状 改为
第 8 行 using BaseGames.Boss; 删(仅为 BossSkillSO
第 80 行 _bossId 字段,注释 kept for legacy SkillSequenceSO queries if any 删(死字段 + 死注释)
第 692706 行 CreateChaoFengSkillSO BossSkillSO,设 skillId / displayName / availablePhaseIndices / weight EnemyAbilitySO类型化子类(按招式类型),设 abilityId / weight / cooldown / category = AbilityCategory.Attack / rangeRadius > 0。阶段索引不再进 SO,改由 BossPhaseAbilityGate 承载
第 709716 行 ChaoFengSkillDefs (name, id, phases, weight) (name, id, soType, rangeRadius, cooldown, weight),与 GetEnemyAbilityDefs 的三元组形式对齐;阶段信息移到放置工具的阶段门配置
第 718727 行 CreateAllChaoFengSOs 提示"检查 BossSkillExecutor._skills 绑定" 改为"检查 EnemyAiBrain._definitionId = ChaoFeng 与各能力组件的 _config 绑定"
第 785801 行 BuildBossStatus FindAtPath<BossSkillSO> FindAtPath<EnemyAbilitySO>;并新增一行 AI 图状态检查(AiDefinitionRegistry 是否含 ChaoFeng
第 365 行 MakeJumpButton("Boss 技能序列查看器", BossSkillSequenceWindow.OpenWindow) 删(窗口已删)
第 367 行 MakeJumpButton("Data HubBoss技能)", …) 改标签为 Data Hub(敌人/能力)BossSkillModule 已删)
第 348 行 放置说明提到 BossSkillExecutor 组件树 改为「ChaoFengBoss + 浮空控制器 + 击倒计数 + EnemyAiBrain + BossPhaseAbilityGate + 5 个能力组件 + HitBox × 4 + 炮口 × 3」

rangeRadius > 0 是硬要求EnemyAbilitySO.Validate()EnemyBase.BuildAttackSelector() 都会 对 category == Attack && rangeRadius <= 0 显式报错(招式永远够不着)。向导必须产出合规值, 不能留 0 让作者事后补——那是把创建链路的责任推给下游(第 6 条)。

8.2 Editor/Scene/SceneObjectPlacerTool.csPlaceChaoFeng,约 10891191 行)

位置 现状 改为
1089 GetOrAddComponent<BossSkillExecutor>(go) 删;改为挂 EnemyAiBrain_definitionId = "ChaoFeng"+ BossPhaseAbilityGate + 5 个能力组件
1098 注释「技能执行时由 BossSkillExecutor 开关」 改为「由各能力组件按 EnemyAttackSO.hitBoxSlot 开关」
11611172 收集 BossSkillSO 赋给 skillExec._skills 改为把 ABL_ChaoFeng_*EnemyAbilitySO)逐个赋给对应能力组件的 _config,并把 HitBox 绑进 MeleeAttackAbility._hitBoxSlots
1169 未找到 BossSkillSO{n} 未找到 EnemyAbilitySO{n}
11861187 提示挂入 BossSkillExecutor._hitBoxes / 拖炮口进 BossSkillSO 改为槽位绑定说明 + 炮口留在 ChaoFengBoss 上(现状已如此,SpawnProjectile 读的是 ChaoFengBoss 的 muzzle 字段)
11901191 提示「技能执行仍由 BossSkillExecutor 负责」 删该括号说明;改为「Boss 走定制路径:_definitionId = ChaoFeng,不用配方」
405407 E004 的提示「★ 挂载 BossSkillExecutor 并指定 BossSkillSO 列表」 删(E004 归属已定为精英怪,走 ApproachAttackEngagement
新增 一并放置 BossFightTrigger(发 EVT_BossFightStarted + brain.Send(AiSignal.Engaged)),否则 Boss 永远不开战(§3.1 缺口)

8.3 顺带一致性修正

EnemyAbilitySO[CreateAssetMenu(fileName = "EAB_")]AssetFolderSpec.md 第 298 行的 ABL_(能力)及两个向导的实际命名都不一致 → 改为 ABL_EnemyAttackSOEATK_ 规范未收录、无冲突,本次不动。


9. 文件清单

删除  Assets/_Game/Scripts/Enemies/Boss/BossSkillSO.cs
删除  Assets/_Game/Scripts/Enemies/Boss/AttackPatternSO.cs
删除  Assets/_Game/Scripts/Enemies/Boss/SkillSequenceSO.cs
删除  Assets/_Game/Scripts/Enemies/Boss/BossSkillExecutor.cs
删除  Assets/_Game/Scripts/Enemies/Boss/BossSkillTypes.cs          (整个文件)
删除  Assets/_Game/Scripts/Enemies/Boss/WeakPointSystem.cs
删除  Assets/_Game/Scripts/Enemies/Boss/Patterns/TelegraphSystem.cs(连带空目录 Patterns/
删除  Assets/_Game/Scripts/Editor/Modules/BossSkillModule.cs
删除  Assets/_Game/Scripts/Editor/Enemies/BossSkillSequenceWindow.cs
删除  Assets/_Game/Data/Enemies/ChaoFeng/Abilities/ABL_ChaoFeng_{Boomerang,FanCombo,TornadoSmall,TornadoLarge,WindStone}.asset

新增  Assets/_Game/Scripts/AI/IBossControl.cs
新增  Assets/_Game/Scripts/Enemies/Boss/BossPhaseAbilityGate.cs
新增  Assets/_Game/Scripts/Enemies/Boss/BossArenaAnchors.cs
新增  Assets/_Game/Scripts/Enemies/Boss/BossFightTrigger.cs
新增  Assets/_Game/Scripts/Enemies/AIBrain/Modules/BossFragments.cs
新增  Assets/_Game/Scripts/Enemies/AIBrain/Ai/ChaoFengAi.cs
新增  Assets/_Game/Data/Enemies/ChaoFeng/Abilities/ABL_ChaoFeng_*.asset  (经向导重建为 EnemyAbilitySO

改    Assets/_Game/Scripts/AI/IAiContext.cs                 + IBossControl Boss
改    Assets/_Game/Scripts/AI/AiSignal.cs                   + Engaged
改    Assets/_Game/Scripts/Enemies/AIBrain/EnemyBrainContext.cs   实现 Boss facet(非 Boss 抛异常)
改    Assets/_Game/Scripts/Enemies/Abilities/AttackSelectionMode.cs        + WeightedRandomAntiRepeat
改    Assets/_Game/Scripts/Enemies/Abilities/EnemyAttackSelector.cs        防重复
改    Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilityBase.cs           CanUse += enabled;删 TelegraphRoutine
改    Assets/_Game/Scripts/Enemies/Abilities/EnemyAbilitySO.cs             + designNote;− telegraph 两字段;fileName → ABL_
改    Assets/_Game/Scripts/Enemies/AIBrain/Modules/Engagement/ApproachAttackEngagement.cs  建态逻辑提静态
改    Assets/_Game/Scripts/Animation/EnemyAnimationEvents.cs   + 4 个 case+ _hurtBox / _feedback 引用
改    Assets/_Game/Scripts/Enemies/EnemyBase.cs            改名 NotifyDecisionStop;− ConsumeParryEvent
改    Assets/_Game/Scripts/Enemies/Behaviors/EnemyDeathSequence.cs         调用点改名
改    Assets/_Game/Scripts/Combat/HurtBox.cs               + 伤害倍率
改    Assets/_Game/Scripts/Enemies/Boss/BossBase.cs        瘦身约 150 行;实现 IBossControl
改    Assets/_Game/Scripts/Enemies/Boss/BossResource.cs     自动触发;+ IsFull
改    Assets/_Game/Scripts/Enemies/Boss/BossResourceConfigSO.cs             自动触发三字段
改    Assets/_Game/Scripts/Enemies/Boss/ChaoFengBoss.cs    StopBehaviorTree() 调用点改为 NotifyDecisionStop()
改    Assets/_Game/Scripts/Editor/Character/CharacterWizardWindow.cs       §8.1
改    Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs           §8.2
测试  Assets/Tests/EditMode/  见 §11
文档  Docs/Guides/02_EnemyBoss  新增一节「Boss AI 怎么写」(定制路径 + 阶段门 + 图片段)

10. 嘲风落地路线

五招的归属:

能力类型 说明
fan_combo MeleeAttackAbility 多段 EATK_HitBox 走槽位
boomerang PlayClipAbility 生成逻辑已在 ChaoFengBoss.SpawnProjectileclip 上挂 SpawnProjectile("boomerang") 动画事件
tornado_small PlayClipAbility 同上
tornado_large PlayClipAbility 同上,落点锁定已实现
wind_stone PlayClipAbility 同上,阶段门只在阶段 1 放行

阶段门配置:地面四招 phases = [0],风石 phases = [1]


11. 测试策略

测试 覆盖
EnemyAttackSelectorTests(扩) WeightedRandomAntiRepeat 的防重复权重分布;上一招被禁用后不参与选招;无正权重时退化路径不变
BossPhaseAbilityGateTests(新) 阶段切换后启用集正确;OnSpawn 回阶段 0;未登记的能力不受影响
ChaoFengAiTests(新) fake IAiContext + fake IBossControl 驱动 AiRuntime,断言 Wait → Intro → Ground ⇄ GroundAttack → PhaseTx → Air ⇄ AirAttack 的状态序列与 trace labelDied 全局边
EnemyBrainContextTests(扩) 非 Boss 敌人访问 IAiContext.BossInvalidOperationException
HurtBoxTests(扩) 伤害倍率生效;默认 1 时行为不变

12. 风险与缓解

风险 缓解
删除面大,中途不可用 分两次提交:先加(六件新增 + 嘲风能力资产 + AI 图跑通 + 两个脚手架改造),确认能打之后再删旧轨整包。任何时刻都有一条能跑的路
删脚本导致资产变 missing script 删除顺序必须先资产后脚本
关闭 Domain Reload 下的陈旧态 BossPhaseAbilityGate 的启用集是纯运行时态,OnSpawn 已重置,无静态态;AiDefinitionRegistry 的静态字典已有 [RuntimeInitializeOnLoadMethod]
弹反反制暂时缺失 §6.2 已列为独立后续任务。现状是"弹反任何敌人 Boss 都硬直"的错误行为,删掉是净改善
能力资产失去编辑器视图 §6.4,后续补 EnemyAbilityModule;本次优先 AiDefinitionValidator
脚手架改造遗漏导致旧轨复活 改完跑三件自检:Validate All ScriptableObjectsValidate Address KeysPhysics2D Layer Matrix/Check;并用向导重建嘲风 5 个资产验证产出合规

13. 注记

  • 本设计推翻 2026-07-27 shared-primitives-decision.md §5 的「执行层按复杂度分层」, 保留其 §2(WeightedPick 抽取)与 §3、§4(冷却 / HitBox 时序不抽)三条结论。
  • 2026-07-29 enemy-ai-composable-modules-design.md §8 把「Boss 双轨统一」列为单独立项, 并注明「E004 归属未定前不动,ApproachAttackEngagement 按精英怪尺度做」。 本次确认 E004 归精英怪,ApproachAttackEngagement 的投入不作废,反而被 Boss 图复用(§4.2)。
  • 竞品调研于 2026-07-30 完成,调研对象与来源链接见对应会话记录;本文档按 CLAUDE.md 第 4 条 只保留功能性描述,不写入具体作品与角色名。