From 9226eb0330183734cdcbeba8c948799dd9a163c4 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Tue, 21 Jul 2026 16:39:16 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=88=A0=E9=99=A4=E8=BF=87=E6=97=B6?= =?UTF-8?q?=E6=8C=87=E5=8D=97=2002(=E6=95=8C=E4=BA=BA=E6=90=AD=E5=BB=BA)?= =?UTF-8?q?=20=E4=B8=8E=2008(BD=20=E8=A1=8C=E4=B8=BA=E6=A0=91=E7=BC=96?= =?UTF-8?q?=E5=86=99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 02_Enemy_Boss_Setup_Guide:敌人框架仍在改动、预制体延后,指南暂删待功能定稿后重写 - 08_BehaviorTree_Authoring_Guide:Behavior Designer 已被自研 BrainGraph HFSM 替换,BD 不再使用 Co-Authored-By: Claude Opus 4.8 (1M context) --- Docs/Guides/02_Enemy_Boss_Setup_Guide.md | 1102 ----------------- .../Guides/08_BehaviorTree_Authoring_Guide.md | 200 --- 2 files changed, 1302 deletions(-) delete mode 100644 Docs/Guides/02_Enemy_Boss_Setup_Guide.md delete mode 100644 Docs/Guides/08_BehaviorTree_Authoring_Guide.md diff --git a/Docs/Guides/02_Enemy_Boss_Setup_Guide.md b/Docs/Guides/02_Enemy_Boss_Setup_Guide.md deleted file mode 100644 index cdaca48a..00000000 --- a/Docs/Guides/02_Enemy_Boss_Setup_Guide.md +++ /dev/null @@ -1,1102 +0,0 @@ -# 小怪与 Boss Unity 配置手册 - -> 文件位置:`Docs/Guides/02_Enemy_Boss_Setup_Guide.md` -> 版本:1.0 · 适用对象:**策划 / 技术美术** -> 对应实现计划:`Docs/Plan/小怪与Boss实现计划-01.md` - -本文档面向在 Unity Editor 中负责创建 Prefab、配置 ScriptableObject、制作动画 Clip、搭建行为树的策划开发者。**所有 C# 脚本均已由程序完成**,本文档只涉及 Editor 操作。 - ---- - -## 目录 - -1. [必读:核心规则(违反会导致运行错误)](#1-必读核心规则) -2. [前置任务:全局配置](#2-前置任务全局配置) -3. [通用操作流程](#3-通用操作流程) -4. [E001 草蛭](#4-e001-草蛭) -5. [E002 簧蛭](#5-e002-簧蛭) -6. [E003 幼蛭](#6-e003-幼蛭) -7. [E004 蛭母(小Boss)](#7-e004-蛭母小boss) -8. [E005 肥蛭(精英怪)](#8-e005-肥蛭精英怪) -9. [E006 讙](#9-e006-讙) -10. [Boss 嘲风](#10-boss-嘲风) -11. [Addressables 注册步骤](#11-addressables-注册步骤) -12. [常见错误排查](#12-常见错误排查) - ---- - -## 1. 必读:核心规则 - -> ⚠️ 在动手之前请完整阅读本节。以下规则违反后**不会有编译错误**,但运行时动画/AI 会失效。 - -### 规则 A:动画永远属于能力脚本,不属于行为树 - -| 正确做法 | 错误做法 | -|---------|---------| -| 技能动画在对应 Ability 组件的字段上绑定 ClipTransition | 在行为树中使用 `BD_PlayAnimation` 节点播放技能动画 | -| 框架状态动画(Idle/Walk/Run/Dead)在 `EnemyAnimationConfigSO` 绑定 | 在行为树中手动切换 Idle、Walk、Run | - -**框架自动负责的动画**(不需要任何操作): - -| 动画 | 自动触发条件 | -|------|------------| -| Idle | `EnemyBase` 初始化时;`BD_SetAiPhase(Idle)` 时 | -| Walk | `BD_SetAiPhase(Patrol)` 时 | -| Run | `BD_SetAiPhase(Chase)` 时;`BD_ChasePlayer` 时 | -| Dead | HP 归零后 `Die()` 自动触发 | - -**结论**:行为树只做**条件判断**(`BD_IsXxx`)和**行为触发**(`BD_UseAbility`、`BD_SetAiPhase`、`BD_MoveToPlayer`)。 - ---- - -### 规则 B:能力组件必须挂在 Prefab 子节点 `Abilities/` 下 - -`EnemyAbilityRegistry` 在游戏开始时自动扫描根节点的所有子 GameObject,收集所有 `EnemyAbilityBase` 子类组件。 -**能力组件挂在根节点本身无法被注册**,必须放在子层级(推荐统一放 `Abilities/` 子节点)。 - ---- - -### 规则 C:abilityId 全局唯一 - -每个 `EnemyAbilitySO` 的 `abilityId` 字段在整个项目中不能重复。推荐命名格式: -`{敌人ID}_{技能描述}` — 例:`e001_activate`、`e004_headslam`、`e006_leap` - ---- - -### 规则 D:命名规范(必须严格遵守) - -| 资产类型 | 命名格式 | 示例 | -|---------|---------|------| -| 敌人 StatsSO | `ENM_{EnemyID}_Stats.asset` | `ENM_E001_Stats.asset` | -| 能力 AbilitySO | `ABL_{EnemyID}_{Name}.asset` | `ABL_E001_Activate.asset` | -| 敌人 Prefab | `ENM_{Name}.prefab` | `ENM_CaoZhi.prefab` | -| 弹体 Prefab | `PROJ_{Name}.prefab` | `PROJ_Boomerang.prefab` | -| 动画 Clip | `{Action}.anim`(无前缀) | `Idle.anim`、`Skill_Start.anim` | -| 精灵图 | `{ID}_{Name}_{Action}.png` | `E001_CaoZhi_Idle.png` | - ---- - -## 2. 前置任务:全局配置 - -在创建任何敌人之前,确认以下全局设置已完成。 - -### 2-A:Layer 确认 - -打开 `Edit → Project Settings → Tags and Layers`,确认以下 Layer 存在: - -| Layer 名 | 用途 | -|---------|------| -| `EnemyHitBox` | 敌人攻击碰撞盒(HitBox 组件) | -| `EnemyHurtBox` | 敌人受击碰撞盒(HurtBox 组件) | -| `EnemyProjectile` | 敌人弹体 | -| `PlayerHitBox` | 玩家攻击碰撞盒 | - -### 2-B:对象池 PoolKey 注册 - -以下弹体/小怪 Prefab 需要注册到对象池(在对象池管理 SO 中添加条目)。Pool Key **必须与 Addressable Address 完全一致**: - -| Pool Key | Prefab | 说明 | -|---------|--------|------| -| `ENM_YouZhi` | `ENM_YouZhi.prefab` | E005 死亡时生成 E003 | -| `PROJ_ZhiMu_Acid` | `PROJ_ZhiMu_Acid.prefab` | E004 酸液弹 | -| `PROJ_FeiZhi_Acid` | `PROJ_FeiZhi_Acid.prefab` | E005 酸液弹 | -| `PROJ_Boomerang` | `PROJ_Boomerang.prefab` | 嘲风回旋扇 | -| `PROJ_TornadoSmall` | `PROJ_TornadoSmall.prefab` | 嘲风小龙卷 | -| `PROJ_TornadoLarge` | `PROJ_TornadoLarge.prefab` | 嘲风大龙卷 | -| `PROJ_WindStone` | `PROJ_WindStone.prefab` | 嘲风风石 | - ---- - -## 3. 通用操作流程 - -每个敌人的创建流程分为以下 5 步,后续章节按此模板展开: - -``` -Step 1 制作动画 Clip -Step 2 创建 ScriptableObject(StatsSO + AbilitySO) -Step 3 搭建 Prefab 结构并配置组件 -Step 4 搭建行为树 -Step 5 注册 Addressables -``` - -### 如何创建 EnemyStatsSO - -右键 `Assets/_Game/Data/Enemies/{EnemyID}/` → **Create → BaseGames/Enemies/Enemy Stats** → 命名 `ENM_{EnemyID}_Stats.asset` - -### 如何创建 EnemyAbilitySO - -右键 `Assets/_Game/Data/Enemies/{EnemyID}/` → **Create → BaseGames/Enemies/Enemy Ability** → 命名 `ABL_{EnemyID}_{Name}.asset` - -### EnemyAnimationConfigSO 标准字段映射 - -| AnimConfig 字段 | 绑定的 Clip | 框架触发时机 | -|----------------|-----------|-----------| -| `Idle` | 待机/伪装 Clip | 游戏开始时;`SetAiPhase(Idle)` | -| `Walk` | 巡逻移动 Clip | `SetAiPhase(Patrol)` | -| `Run` | 追击/快速移动 Clip | `SetAiPhase(Chase)` | -| `Turn` | 转身 Clip | `EnemyMovement` 检测到方向变化(需开启 `_enableTurnAnimation`) | -| `Dead` | 死亡 Clip | `Die()` | -| `Hurt` | 受击 Clip | 框架受击状态 | -| `Stagger` | 硬直 Clip | 框架硬直状态 | - -> ⚠️ 技能动画(如 `Skill_Start`、`Skill_Loop`)**不放在 AnimConfig**,而是直接绑定到各 Ability 组件的 `ClipTransition` 字段。 - ---- - -## 4. E001 草蛭 - -**设计要点**:默认伪装为环境装饰,感知玩家后激活,进入 Skill_Start→Skill_Loop 追击模式。 - -### Step 1:制作动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/E001/Animations/` - -| Clip 文件名 | 用途 | 绑定位置 | -|-----------|------|---------| -| `Idle.anim` | 伪装待机(循环) | AnimConfig.Idle | -| `Move.anim` | 巡逻爬行(循环) | AnimConfig.Walk | -| `Flip.anim` | 转身(单次) | AnimConfig.Turn | -| `Skill_Start.anim` | 激活前摇(单次) | `PlayClipAbility._clip` | -| `Skill_Loop.anim` | 追击循环(循环) | `ContactChaseAbility._loopClip` | -| `Skill_End.anim` | 追击收招(单次) | `ContactChaseAbility._endClip` | -| `Death.anim` | 死亡(单次) | AnimConfig.Dead | - -### Step 2:创建 ScriptableObject - -**文件路径**:`Assets/_Game/Data/Enemies/E001/` - -**`ENM_E001_Stats.asset`**(EnemyStatsSO): - -| 字段 | 说明 | -|-----|------| -| MaxHP | 策划填写 | -| WalkSpeed | 巡逻速度 | -| RunSpeed | 追击速度 | -| DetectRange | 感知范围(与 aggro 传感器半径一致) | - -**`ABL_E001_Activate.asset`**(EnemyAbilitySO): - -| 字段 | 值 | -|-----|---| -| abilityId | `"e001_activate"` | -| cooldown | `0` | -| interruptOnHurt | `true` | - -**`ABL_E001_Chase.asset`**(EnemyAbilitySO): - -| 字段 | 值 | -|-----|---| -| abilityId | `"e001_chase"` | -| cooldown | `0` | -| preferredMaxRange | 与 aggro 传感器半径一致 | - -### Step 3:搭建 Prefab - -**路径**:`Assets/_Game/Prefabs/Enemies/E001/ENM_CaoZhi.prefab` - -**Prefab 层级结构**: - -``` -ENM_CaoZhi (根节点) -├── 组件:EnemyBase、EnemyMovement、EnemyNavAgent、NavAgent、TransformBasedMovement -├── 组件:EnemySensorHub -├── 组件:Rigidbody2D(Dynamic)、Collider2D(主碰撞体) -├── HurtBox/ -│ ├── 组件:HurtBox、Collider2D(Is Trigger=true, Layer=EnemyHurtBox) -├── ContactDamageZone/ -│ ├── 组件:BodyContactDamage(默认常驻 enabled=true)、HitBox、Collider2D(Is Trigger=true, Layer=EnemyHitBox) -└── Abilities/ - ├── 子节点 Activate_Ability → 组件:PlayClipAbility - └── 子节点 Chase_Ability → 组件:ContactChaseAbility -``` - -**组件配置详情**: - -**EnemyBase**: -- `_stats`:拖入 `ENM_E001_Stats.asset` -- `_animConfig`:拖入对应 `EnemyAnimationConfigSO`(需先创建,绑定 Idle/Walk/Run/Turn/Dead Clip) - -**EnemyMovement**: -- `_enableTurnAnimation`:勾选 ✓(使用 Flip 转身动画) - -**EnemySensorHub**(在 Inspector 中添加 `_slots`): - -| slotName | Sensor 类型 | 说明 | -|---------|-----------|------| -| `aggro` | RangeSensor2D | 感知半径 = DetectRange | -| `wall_ahead` | RaySensor2D | 向前射线,检测墙壁 | -| `ledge` | RaySensor2D | 向前下方射线,检测悬崖 | - -**PlayClipAbility**(挂在 `Activate_Ability` 子节点): -- `_config`:拖入 `ABL_E001_Activate.asset` -- `_clip`:拖入 `Skill_Start.anim` 对应的 ClipTransition - -**ContactChaseAbility**(挂在 `Chase_Ability` 子节点): -- `_config`:拖入 `ABL_E001_Chase.asset` -- `_loopClip`:`Skill_Loop.anim` -- `_endClip`:`Skill_End.anim` -- `_sensorHub`:拖入根节点上的 `EnemySensorHub` 组件 -- `_aggroSlotName`:`"aggro"` - -### Step 4:搭建行为树 - -在根节点挂载 `BehaviorTree` 组件,创建如下结构: - -``` -Selector -├── Sequence [死亡] -│ ├── BD_IsStateMatch → State: Dead -│ └── BD_StopMovement -│ -├── Sequence [激活] -│ ├── Selector -│ │ ├── BD_IsAiPhase → Phase: Idle -│ │ └── BD_IsAiPhase → Phase: Patrol -│ ├── BD_IsSensorDetecting → SlotName: "aggro" -│ ├── BD_UseAbility → AbilitySO: ABL_E001_Activate -│ └── BD_SetAiPhase → Phase: Chase -│ -├── Sequence [追击] -│ ├── BD_IsAiPhase → Phase: Chase -│ └── BD_UseAbility → AbilitySO: ABL_E001_Chase -│ -└── Selector [巡逻] - ├── Sequence [待机] - │ ├── BD_IsAiPhase → Phase: Idle - │ └── BD_WaitRandom → Min/Max: 填写待机时长范围 - └── Sequence [移动] - ├── BD_IsAiPhase → Phase: Patrol - └── BD_Patrol -``` - -> ⚠️ 最外层巡逻节点必须是 **Selector** 而不是 Sequence。否则待机结束后不会进入巡逻分支。 - -### Step 5:注册 Addressables - -- Address:`ENM_CaoZhi` -- Group:`Enemies` -- Labels:`Enemy` - ---- - -## 5. E002 簧蛭 - -**设计要点**:固定位置(悬挂天花板),无移动能力。Skill_Loop 期间为脆弱窗口(HurtBox 开启)。 - -### Step 1:动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/E002/Animations/` - -| Clip 文件名 | 用途 | 绑定位置 | -|-----------|------|---------| -| `Idle.anim` | 待机(循环) | AnimConfig.Idle | -| `Skill_Strike.anim` | 出击(单次) | `CeilingHangStrikeAbility._strikeClip` | -| `Skill_Loop.anim` | 脆弱悬挂(循环) | `CeilingHangStrikeAbility._loopClip` | -| `Skill_End.anim` | 收回(单次) | `CeilingHangStrikeAbility._endClip` | -| `Death.anim` | 死亡 | AnimConfig.Dead | - -### Step 2:ScriptableObject - -路径:`Assets/_Game/Data/Enemies/E002/` - -**`ENM_E002_Stats.asset`**:WalkSpeed/RunSpeed=0(固定单位)。 - -**`ABL_E002_CeilingStrike.asset`**: - -| 字段 | 值 | -|-----|---| -| abilityId | `"e002_ceiling_strike"` | -| cooldown | 悬挂时长+恢复时长(策划填写) | -| interruptOnHurt | `false`(技能期间霸体) | - -在 `attackSequence` 数组添加一个条目: -- `clip`:`Skill_Strike.anim` -- `damageSource`:拖入对应的 `DamageSourceSO`(定义伤害量/类型) - -### Step 3:搭建 Prefab - -路径:`Assets/_Game/Prefabs/Enemies/E002/ENM_HuangZhi.prefab` - -``` -ENM_HuangZhi (根节点) -├── 组件:EnemyBase ← 注意:不挂 EnemyMovement、NavAgent -├── 组件:EnemySensorHub -├── 组件:Rigidbody2D(Kinematic,Gravity Scale=0) -├── HurtBox/ -│ ├── 组件:HurtBox(初始 enabled=false)、Collider2D -└── Abilities/ - └── 子节点 CeilingStrike_Ability → 组件:CeilingHangStrikeAbility -``` - -> ⚠️ E002 **不挂** `EnemyMovement`、`EnemyNavAgent`、`NavAgent`、`TransformBasedMovement`,因为它是固定单位。 - -**CeilingHangStrikeAbility 配置**: -- `_config`:`ABL_E002_CeilingStrike.asset` -- `_strikeClip`:`Skill_Strike.anim` -- `_loopClip`:`Skill_Loop.anim` -- `_endClip`:`Skill_End.anim` -- `_attackHitBox`:拖入 `AttackHitBox/` 子节点的 HitBox 组件 -- `_hurtBox`:拖入 `HurtBox/` 子节点的 HurtBox 组件 -- `_hangDuration`:脆弱悬挂时长(秒,策划填写) - -**EnemySensorHub**: - -| slotName | Sensor 类型 | 说明 | -|---------|-----------|------| -| `attack_range` | RangeSensor2D | 正下方矩形区域,检测玩家是否在正下方 | - -### Step 4:行为树 - -``` -Selector -├── Sequence [死亡] -│ ├── BD_IsStateMatch → Dead -│ └── BD_Wait → Duration: 999 -│ -└── Sequence [攻击] - ├── BD_IsSensorDetecting → SlotName: "attack_range" - ├── BD_CanUseAbility → AbilitySO: ABL_E002_CeilingStrike - └── BD_UseAbility → AbilitySO: ABL_E002_CeilingStrike -``` - -### Step 5:Addressables - -- Address:`ENM_HuangZhi` · Group:`Enemies` · Labels:`Enemy` - ---- - -## 6. E003 幼蛭 - -**设计要点**:HP=1(一击即死)。支持两种生成路径: -① 场景预置(悬挂天花板,触发器激活) -② E005 肥蛭死亡时从代码生成。 -生成后从天花板落下(Kinematic → Dynamic),落地后开始地面追击。 - -### Step 1:动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/E003/Animations/` - -| Clip 文件名 | 用途 | 绑定位置 | -|-----------|------|---------| -| `Idle.anim` | 天花板吸附待机(循环) | AnimConfig.Idle | -| `Fall.anim` | 下落旋转(循环,直到落地) | `AnimatedCeilingDropAbility._fallLoopClip` | -| `Move.anim` | 地面移动(循环) | AnimConfig.Walk | -| `Skill.anim` | 追击加速(循环) | AnimConfig.Run | -| `Death.anim` | 死亡 | AnimConfig.Dead | - -### Step 2:ScriptableObject - -路径:`Assets/_Game/Data/Enemies/E003/` - -**`ENM_E003_Stats.asset`**:MaxHP=**1**(一击即死) - -**`ABL_E003_Fall.asset`**: - -| 字段 | 值 | -|-----|---| -| abilityId | `"e003_fall"` | -| cooldown | `0` | - -### Step 3:Prefab - -路径:`Assets/_Game/Prefabs/Enemies/E003/ENM_YouZhi.prefab` - -``` -ENM_YouZhi (根节点) -├── 组件:EnemyBase、EnemyAbilityTrigger、EnemyMovement、EnemyNavAgent、NavAgent、TransformBasedMovement -├── 组件:EnemySensorHub -├── 组件:Rigidbody2D(初始 Body Type=Kinematic,下落能力会自动切换为 Dynamic) -├── HurtBox/ -├── ContactDamageZone/ -│ └── 组件:BodyContactDamage(默认常驻 enabled=true;存活即身体接触伤害,与能力解耦,死亡时经 PerformDeath 统一关碰撞体停止) -└── Abilities/ - └── 子节点 Fall_Ability → 组件:AnimatedCeilingDropAbility -``` - -**AnimatedCeilingDropAbility 配置**: - -| 字段 | 值 | -|-----|---| -| `_config` | `ABL_E003_Fall.asset` | -| `_fallLoopClip` | `Fall.anim` | -| `_fallGravityScale` | `3.5`(策划可调) | -| `_maxFallTime` | `3`(超时保护) | -| `_groundMask` | 选择 `Ground` Layer | -| `_recoveryTime` | `0.1`(落地后短暂停顿) | - -**EnemyAbilityTrigger 组件配置**(零代码出生/触发执行能力,替代过去的 E003_YouZhi 专属脚本): -- `_abilityId`:`e003_fall`(与 `ABL_E003_Fall.asset` 的 `abilityId` 一致) -- `_executeOnSpawn`:勾选 ✓(对象池生成时自动触发下落) -- 若是场景预置(非对象池),由场景战斗触发器 / UnityEvent / 动画事件调用本组件的 `Trigger()` 方法激活下落 - -**EnemySensorHub**: - -| slotName | 类型 | -|---------|------| -| `aggro` | RangeSensor2D | - -### Step 4:行为树 - -``` -Selector -├── Sequence [死亡] -│ ├── BD_IsStateMatch → Dead -│ └── BD_StopMovement -│ -├── Sequence [下落(Idle 阶段,一次性)] -│ ├── BD_IsAiPhase → Idle -│ └── BD_UseAbility → ABL_E003_Fall ← 落地后能力内部自动 SetAiPhase(Patrol) -│ -├── Sequence [感知追击] -│ ├── BD_IsSensorDetecting → "aggro" -│ └── BD_ChasePlayer ← 自动 SetAiPhase(Chase)+播 AnimConfig.Run -│ -└── BD_Patrol ← 兜底巡逻,自动 SetAiPhase(Patrol)+播 AnimConfig.Walk -``` - -### Step 5:Addressables - -- Address:`ENM_YouZhi` · Group:`Enemies` · Labels:`Enemy`, `Poolable`, `Preload` - -> ⚠️ E003 必须标记 `Poolable` 和 `Preload`,因为 E005 死亡时会从对象池动态生成它。 - ---- - -## 7. E004 蛭母(小Boss) - -**设计要点**:拥有出场演出、三种战斗技能(撕咬/头槌/酸液)、翻身能力(玩家绕后时触发),死亡分两阶段(Death_Pre 无敌演出 → 真正死亡)。 - -### Step 1:动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/E004/Animations/` - -| Clip 文件名 | 用途 | 绑定位置 | -|-----------|------|---------| -| `Static.anim` | 休眠待机(1帧循环) | AnimConfig.Idle | -| `Move.anim` | 战斗移动(循环) | AnimConfig.Walk | -| `Appear.anim` | 出场嚎叫(单次) | `AppearAbility._appearClip` | -| `Skill01.anim` | 撕咬(单次) | `MeleeAttackAbility.attackSequence[0].clip` | -| `Skill02_Start.anim` | 头槌起手(单次) | `RepeatSlamAbility._startClip` | -| `Skill02_Loop.anim` | 头槌砸地(单次,循环N次) | `RepeatSlamAbility._loopClip` | -| `Skill02_End.anim` | 头槌收招(单次) | `RepeatSlamAbility._endClip` | -| `Skill03.anim` | 吐酸液(单次) | `ProjectileAttackAbility.attackSequence[0/1].clip` | -| `Flip.anim` | 翻身转向(单次) | `FacePlayerAbility._faceClip` | -| `Death_Pre.anim` | 死亡前摇(循环,约3秒) | `EnemyDeathSequence._deathPreClip` | -| `Death.anim` | 死亡消散(单次) | AnimConfig.Dead | - -### Step 2:ScriptableObject - -路径:`Assets/_Game/Data/Enemies/E004/` - -| 文件名 | abilityId | 关键配置 | -|-------|-----------|---------| -| `ENM_E004_Stats.asset` | — | HP/速度/感知范围 | -| `ABL_E004_Appear.asset` | `"e004_appear"` | cooldown=0 | -| `ABL_E004_Bite.asset` | `"e004_bite"` | preferredMaxRange=近战半径;attackSequence[0] 绑定 DamageSourceSO | -| `ABL_E004_HeadSlam.asset` | `"e004_headslam"` | preferredMaxRange=中距半径;interruptOnHurt=false(霸体) | -| `ABL_E004_Acid.asset` | `"e004_acid"` | preferredMinRange=2 | -| `ABL_E004_Flip.asset` | `"e004_flip"` | cooldown=0.3 | - -### Step 3:Prefab - -路径:`Assets/_Game/Prefabs/Enemies/E004/ENM_ZhiMu.prefab` - -``` -ENM_ZhiMu (根节点) -├── 组件:EnemyBase、EnemyDeathSequence、EnemyMovement、EnemyNavAgent、NavAgent、TransformBasedMovement -├── 组件:EnemySensorHub -├── 组件:EnemyFeedback、Rigidbody2D -├── HurtBox/ → 组件:HurtBox、Collider2D -├── BiteHitBox/ → 组件:HitBox、Collider2D(撕咬用) -├── SlamHitBox/ → 组件:HitBox、Collider2D(头槌用) -├── AcidMuzzle/ → 空 Transform(酸液发射点) -└── Abilities/ - ├── Appear_Ability → 组件:AppearAbility - ├── Bite_Ability → 组件:MeleeAttackAbility - ├── HeadSlam_Ability → 组件:RepeatSlamAbility - ├── Acid_Ability → 组件:ProjectileAttackAbility - └── Flip_Ability → 组件:FacePlayerAbility -``` - -**EnemyDeathSequence 组件配置**(零代码死亡前摇无敌演出,替代过去的 E004_ZhiMu 专属 Die() 重写): -- `_deathPreClip`:拖入 `Death_Pre.anim` -- `_duration`:`3`(与 Death_Pre 动画时长一致,策划调整) -- `_hurtBoxesToDisable`:拖入 `HurtBox/` 组件(演出期间停用,对象池复用时出生自动恢复) -- `_stopBehaviorTree` / `_stopMovement`:默认勾选(演出期间停 BT 与移动) - -**AppearAbility**: -- `_config`:`ABL_E004_Appear.asset` -- `_appearClip`:`Appear.anim` - -**MeleeAttackAbility**(撕咬): -- `_config`:`ABL_E004_Bite.asset` -- 在 ABL_E004_Bite 的 `attackSequence[0]` 中: - - `clip`:`Skill01.anim` - - `hitBoxSlot`:`"bite"`(与 `_hitBoxSlots` 中的 slotName 对应) - - `hitBoxEnterT`:`0.30`(Clip 时长的 30% 时激活 HitBox) - - `hitBoxExitT`:`0.60`(Clip 时长的 60% 时停用 HitBox) -- 在 MeleeAttackAbility 的 `_hitBoxSlots` 中添加:slotName=`"bite"`, hitBox=拖入 `BiteHitBox/` - -**RepeatSlamAbility**(头槌): -- `_config`:`ABL_E004_HeadSlam.asset` -- `_startClip`:`Skill02_Start.anim` -- `_loopClip`:`Skill02_Loop.anim` -- `_endClip`:`Skill02_End.anim` -- `_hitBox`:拖入 `SlamHitBox/` -- `_slamCount`:`2`(策划调整) -- `_hitActiveTime`:`0.15` -- `_staggerDuration`:`1.2`(收招后硬直,供玩家反击) - -**ProjectileAttackAbility**(酸液): -- `_config`:`ABL_E004_Acid.asset` -- `_muzzle`:拖入 `AcidMuzzle/` Transform -- ABL_E004_Acid 的 `attackSequence[0]`: - - `clip`:`Skill03.anim` - - `projectileCount`:`3`(同时发射数量) - - `spreadAngleDeg`:`30`(扩散角) - - `projectileFireT`:`0.5`(Clip 的 50% 时发射) - - `projectileConfig`:指向 `PROJ_ZhiMu_Acid` 的弹体配置 SO - -**FacePlayerAbility**(翻身): -- `_config`:`ABL_E004_Flip.asset` -- `_faceClip`:`Flip.anim` - -**EnemySensorHub**: - -| slotName | 类型 | -|---------|------| -| `aggro` | RangeSensor2D | -| `los` | LOSSensor2D | - -### Step 4:行为树 - -``` -Selector -├── Sequence [死亡] -│ ├── BD_IsStateMatch → Dead -│ └── BD_StopMovement -│ -├── Sequence [出场(仅首次,Idle阶段)] -│ ├── BD_IsAiPhase → Idle -│ └── BD_UseAbility → ABL_E004_Appear ← 内部自动 SetAiPhase(Combat) -│ -└── Sequence [战斗] - ├── BD_IsAiPhase → Combat - └── Selector - ├── Sequence [翻身(技能间隙+玩家在背后)] - │ ├── BD_CanUseAbility → ABL_E004_Flip ← CanUse 内部已检测无技能运行且玩家在背后 - │ └── BD_UseAbility → ABL_E004_Flip - │ - ├── Sequence [撕咬(近距)] - │ ├── BD_CanUseAbility → ABL_E004_Bite, CheckRange=true - │ └── BD_UseAbility → ABL_E004_Bite - │ - ├── Sequence [头槌(中距)] - │ ├── BD_CanUseAbility → ABL_E004_HeadSlam, CheckRange=true - │ └── BD_UseAbility → ABL_E004_HeadSlam - │ - ├── Sequence [酸液(远程)] - │ ├── BD_CanUseAbility → ABL_E004_Acid - │ └── BD_UseAbility → ABL_E004_Acid - │ - └── BD_MoveToPlayer -``` - -> ⚠️ `BD_CanUseAbility(ABL_E004_Flip)` 无需额外检测"无其他技能运行",该逻辑已内置在 `FacePlayerAbility.CanUse` 中。 - -### Step 5:Addressables - -- Address:`ENM_ZhiMu` · Group:`Enemies` · Labels:`Enemy` - ---- - -## 8. E005 肥蛭(精英怪) - -**设计要点**:撕咬技能有后摇脆弱窗口(HurtBox 激活),死亡时 Death_Pre 动画中通过 AnimationEvent 生成多只 E003。 - -### Step 1:动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/E005/Animations/` - -| Clip 文件名 | 用途 | 绑定位置 | -|-----------|------|---------| -| `Idle.anim` | 待机(循环) | AnimConfig.Idle | -| `Move.anim` | 移动(循环) | AnimConfig.Walk/Run | -| `Skill01.anim` | 撕咬(单次) | `MeleeVulnerabilityAbility._attackClip` | -| `Skill02.anim` | 吐酸液(单次,连续两轮复用) | `ProjectileAttackAbility.attackSequence[0/1].clip` | -| `Death_Pre.anim` | 死亡前摇(含 AnimationEvent) | `EnemyDeathSequence._deathPreClip` | -| `Death.anim` | 死亡 | AnimConfig.Dead | - -> ⚠️ **Death_Pre AnimationEvent 设置(关键步骤)**: -> 1. 在 Unity 动画编辑器中打开 `Death_Pre.anim` -> 2. 在适当帧(E003 应该出现的时刻)添加 AnimationEvent -> 3. 函数名:`SpawnProjectile`,字符串参数:`"spawn_e003"` - -### Step 2:ScriptableObject - -路径:`Assets/_Game/Data/Enemies/E005/` - -| 文件名 | abilityId | 配置 | -|-------|-----------|------| -| `ENM_E005_Stats.asset` | — | HP/速度 | -| `ABL_E005_Bite.asset` | `"e005_bite"` | preferredMaxRange=近战半径 | -| `ABL_E005_Acid.asset` | `"e005_acid"` | 无范围限制 | - -### Step 3:Prefab - -路径:`Assets/_Game/Prefabs/Enemies/E005/ENM_FeiZhi.prefab` - -``` -ENM_FeiZhi (根节点) -├── 组件:EnemyBase、EnemyDeathSequence、EnemySpawnerOnEvent、EnemyMovement、EnemyNavAgent、NavAgent、TransformBasedMovement -├── 组件:EnemySensorHub -├── 组件:Rigidbody2D -├── HurtBox/ → 组件:HurtBox -├── BiteHitBox/ → 组件:HitBox -├── AcidMuzzle/ → 空 Transform -└── Abilities/ - ├── Bite_Ability → 组件:MeleeVulnerabilityAbility - └── Acid_Ability → 组件:ProjectileAttackAbility -``` - -**EnemyDeathSequence 配置**(零代码死亡前摇无敌演出): -- `_deathPreClip`:`Death_Pre.anim` -- `_duration`:与动画时长一致 -- `_hurtBoxesToDisable`:`HurtBox/` 组件 - -**EnemySpawnerOnEvent 配置**(零代码动画事件池生成,替代过去的 E005_FeiZhi 专属 SpawnProjectile 重写): -- `_payloadKey`:`spawn_e003`(与 Death_Pre 动画事件 payload 一致) -- `_poolKey`:`ENM_YouZhi`(对象池 key) -- `_count`:`3`(生成幼蛭数量,策划调整) -- `_radius`:`1.5`(生成散布半径) - -**MeleeVulnerabilityAbility(撕咬)**: -- `_config`:`ABL_E005_Bite.asset` -- `_attackClip`:`Skill01.anim` -- `_hitBox`:`BiteHitBox/` -- `_hurtBox`:`HurtBox/`(后摇期间开放脆弱窗口) -- `_hitEnterT`:`0.30`(攻击 30% 时激活 HitBox) -- `_hitExitT`:`0.60`(攻击 60% 时停用 HitBox) -- `_staggerDuration`:`1.0`(后摇脆弱窗口时长,策划调整) - -**ProjectileAttackAbility(酸液,连续两次)**: -- `_config`:`ABL_E005_Acid.asset` -- `_muzzle`:`AcidMuzzle/` -- ABL_E005_Acid 的 `attackSequence`(需要 **2 个条目**): - - `[0]`:clip=`Skill02.anim`, projectileCount=1, projectileFireT=0.6, postDelay=0.2 - - `[1]`:clip=`Skill02.anim`, projectileCount=1, projectileFireT=0.6 - -> ⚠️ 设计要求"连续两次吐出"必须用 **2个 attackSequence 条目**,每条发射1颗。如果用 projectileCount=2 会同帧射出 2 颗,不是连续动作。 - -### Step 4:行为树 - -``` -Selector -├── Sequence [死亡] -│ ├── BD_IsStateMatch → Dead -│ └── BD_StopMovement -│ -├── Sequence [撕咬(近距)] -│ ├── BD_CanUseAbility → ABL_E005_Bite, CheckRange=true -│ └── BD_UseAbility → ABL_E005_Bite -│ -├── Sequence [酸液(远程)] -│ ├── BD_CanUseAbility → ABL_E005_Acid -│ └── BD_UseAbility → ABL_E005_Acid -│ -└── BD_ChasePlayer ← 自动 SetAiPhase(Chase)+播 AnimConfig.Run -``` - -### Step 5:Addressables - -- Address:`ENM_FeiZhi` · Group:`Enemies` · Labels:`Enemy` - ---- - -## 9. E006 讙 - -**设计要点**:跳跃攻击(动画原地,Rigidbody2D 冲量负责实际位移)。Flip 由巡逻转身自动处理,无需专用 Ability。 - -### Step 1:动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/E006/Animations/` - -| Clip 文件名 | 用途 | 绑定位置 | -|-----------|------|---------| -| `Idle.anim` | 待机 | AnimConfig.Idle | -| `Move.anim` | 巡逻移动 | AnimConfig.Walk | -| `Flip.anim` | 转身 | AnimConfig.Turn | -| `Skill.anim` | 跳跃攻击(含起跳/飞行/落地姿态) | `LeapAttackAbility`(attackSequence[0].clip) | -| `Death.anim` | 死亡 | AnimConfig.Dead | - -### Step 2:ScriptableObject - -路径:`Assets/_Game/Data/Enemies/E006/` - -**`ABL_E006_Leap.asset`**: - -| 字段 | 值 | -|-----|---| -| abilityId | `"e006_leap"` | -| cooldown | 攻击间隔(策划填写) | -| attackSequence[0].clip | `Skill.anim` | - -### Step 3:Prefab - -路径:`Assets/_Game/Prefabs/Enemies/E006/ENM_Huan.prefab` - -``` -ENM_Huan (根节点) -├── 组件:EnemyBase、EnemyMovement、EnemyNavAgent、NavAgent、TransformBasedMovement -├── 组件:EnemySensorHub -├── 组件:Rigidbody2D(Dynamic) -├── HurtBox/ -├── LandingHitBox/ → 组件:HitBox(落地时的攻击判定) -└── Abilities/ - └── Leap_Ability → 组件:LeapAttackAbility -``` - -**EnemyMovement**: -- `_enableTurnAnimation`:勾选 ✓ - -**LeapAttackAbility 配置**: -- `_config`:`ABL_E006_Leap.asset` -- `_jumpHeight`、`_maxRange`:策划填写 -- `_windupTime`:起跳前摇时间(秒) -- `_recoveryTime`:落地硬直时间 -- `_groundMask`:Ground Layer -- `_landingHitBox`:拖入 `LandingHitBox/` - -**EnemySensorHub**: - -| slotName | 类型 | -|---------|------| -| `aggro` | RangeSensor2D | -| `wall_ahead` | RaySensor2D | -| `ledge` | RaySensor2D | - -### Step 4:行为树 - -``` -Selector -├── Sequence [死亡] -│ ├── BD_IsStateMatch → Dead -│ └── BD_StopMovement -│ -├── Sequence [跳跃攻击] -│ ├── BD_IsSensorDetecting → "aggro" -│ ├── BD_CanUseAbility → ABL_E006_Leap -│ └── BD_UseAbility → ABL_E006_Leap -│ -└── BD_Patrol ← wall_ahead + ledge 槽驱动翻转(含 Turn 动画) -``` - -### Step 5:Addressables - -- Address:`ENM_Huan` · Group:`Enemies` · Labels:`Enemy` - ---- - -## 10. Boss 嘲风 - -**设计要点**: -- **Phase 0(地面)**:4 技能加权随机(回旋扇/扇形连击/小龙卷/大龙卷) -- **Phase 1(空中)**:HP 低于 50% 触发过渡,进入悬浮阶段,使用风石技能 + 击落机制 -- **击落机制**:Phase 1 被命中 N 次后触发击落序列(落地硬直→恢复浮空) -- **击败演出**:完整的 4 段过场动画序列 - -### Step 1:动画 Clip - -路径:`Assets/_Game/Art/Characters/Enemies/ChaoFeng/Animations/` - -**状态动画**(绑定 AnimConfig): - -| Clip 文件名 | AnimConfig 字段 | -|-----------|----------------| -| `Idle.anim` | Idle | -| `Move.anim` | Walk | -| `Dead.anim` | Dead | - -**技能动画**(绑定 BossSkillSO.skillAnimation): - -| Clip 文件名 | 对应技能 | -|-----------|--------| -| `Boomerang.anim` | 回旋扇主动画 | -| `Boomerang_End.anim` | 回旋扇收招(绑定 `ChaoFengBoss._boomerangEndClip`) | -| `FanCombo_01.anim`~`FanCombo_03.anim` | 扇形三连击各段 | -| `TornadoSmall.anim` | 小龙卷 | -| `TornadoLarge.anim` | 大龙卷 | -| `WindStone.anim` | 风石(Phase 2 专属) | - -**过渡/演出动画**(绑定 ChaoFengBoss 字段): - -| Clip 文件名 | 绑定字段 | -|-----------|--------| -| `PhaseTransition.anim` | `_phaseTransitionClip`(上浮过渡动画) | -| `KnockdownHit.anim` | `ChaoFengKnockdownCounter._knockdownHitClip`(被打落时) | -| `Stagger.anim` | `ChaoFengKnockdownCounter._staggerClip`(落地硬直,复用为 Defeat_Pant) | -| `Defeat_Struggle.anim` | `_defeatStruggleClip`(击败时空中挣扎) | -| `Defeat_Pant.anim` | `_defeatPantClip`(倒地喘气) | -| `Defeat_StandUp.anim` | `_defeatStandUpClip`(站起) | - -### Step 2:ScriptableObject(BossSkillSO) - -路径:`Assets/_Game/Data/Enemies/ChaoFeng/` - -> ⚠️ 嘲风使用 **BossSkillSO**(不是 EnemyAbilitySO)。右键 → **Create → BaseGames/Boss/Boss Skill** - -| 文件名 | skillId | availablePhaseIndices | weight | -|-------|---------|----------------------|--------| -| `ABL_ChaoFeng_Boomerang.asset` | `"boomerang"` | `[0]` | `1.0` | -| `ABL_ChaoFeng_FanCombo.asset` | `"fan_combo"` | `[0]` | `1.5` | -| `ABL_ChaoFeng_TornadoSmall.asset` | `"tornado_small"` | `[0]` | `1.2` | -| `ABL_ChaoFeng_TornadoLarge.asset` | `"tornado_large"` | `[0]` | `0.8` | -| `ABL_ChaoFeng_WindStone.asset` | `"wind_stone"` | `[1]` | Phase 2 专属 | - -每个 BossSkillSO 的 `skillAnimation` 字段绑定对应 Clip。 - -**`ENM_ChaoFeng_Stats.asset`**:HP/速度。 - -### Step 3:弹体 Prefab - -在制作嘲风 Prefab 之前,需要先创建弹体。 - -#### PROJ_Boomerang.prefab - -路径:`Assets/_Game/Prefabs/Combat/Projectiles/PROJ_Boomerang.prefab` - -``` -PROJ_Boomerang (根节点) -├── 组件:ReturnProjectile(C# 脚本,继承 Projectile) -├── 组件:Rigidbody2D(Dynamic) -├── 组件:PooledObject(必须,用于对象池回收) -└── HitBox/ → 组件:HitBox、Collider2D(Layer=EnemyProjectile) -``` - -**ReturnProjectile 配置**: -- `_maxRange`:最大飞行距离(策划填写) -- `_returnSpeed`:返回速度(策划填写) -- `_config`:弹体配置 SO(`ProjectileConfigSO`,设置 Speed/Lifetime/DamageSource) - -> ⚠️ Addressables 配置:Address=`PROJ_Boomerang`, Group=`Projectiles`, Labels=`Poolable`, `Preload` - -#### 其他弹体 Prefab - -`PROJ_TornadoSmall`、`PROJ_TornadoLarge`、`PROJ_WindStone`:使用现有 Projectile 脚本,配置方式参考项目中已有的弹体。 - -### Step 4:搭建嘲风 Prefab - -路径:`Assets/_Game/Prefabs/Enemies/ChaoFeng/ENM_ChaoFeng.prefab` - -``` -ENM_ChaoFeng (根节点) -├── 组件:ChaoFengBoss(C# 脚本) -├── 组件:EnemyMovement -├── 组件:EnemyNavAgent、NavAgent、TransformBasedMovement -├── 组件:BossSkillExecutor(Boss 技能执行器) -├── 组件:ChaoFengFloatController(浮空控制器) -├── 组件:ChaoFengKnockdownCounter(击落计数器) -├── 组件:EnemyFeedback -├── 组件:Rigidbody2D(Dynamic,击落/落地时由 ChaoFengFloatController 切换为 Kinematic) -├── HurtBox/ → 组件:HurtBox -├── Phase1HitBoxes/ -│ ├── FanCombo_HitBox_1/ → HitBox -│ ├── FanCombo_HitBox_2/ → HitBox -│ ├── FanCombo_HitBox_3/ → HitBox -│ └── Tornado_HitBox/ → HitBox -├── Muzzles/ -│ ├── BoomerangMuzzle/ → 空 Transform(回旋扇发射点) -│ ├── TornadoMuzzle/ → 空 Transform -│ └── WindStoneMuzzle/ → 空 Transform -└── BehaviorTree [BehaviorDesigner 组件] -``` - -**ChaoFengBoss 字段配置**: - -| 字段 | 拖入内容 | -|-----|---------| -| `_floatController` | 根节点 ChaoFengFloatController 组件 | -| `_knockdownCounter` | 根节点 ChaoFengKnockdownCounter 组件 | -| `_phaseTransitionClip` | `PhaseTransition.anim` | -| `_boomerangEndClip` | `Boomerang_End.anim` | -| `_boomerangMuzzle` | `Muzzles/BoomerangMuzzle` Transform | -| `_tornadoMuzzle` | `Muzzles/TornadoMuzzle` Transform | -| `_windStoneMuzzle` | `Muzzles/WindStoneMuzzle` Transform | -| `_defeatStruggleClip` | `Defeat_Struggle.anim` | -| `_defeatPantClip` | `Defeat_Pant.anim` | -| `_defeatStandUpClip` | `Defeat_StandUp.anim` | -| `_defeatPantDuration` | `3`(倒地喘气时长,策划调整) | -| `_onDefeatWhiteFlash` | 拖入白屏效果的 UnityEvent 接收者(可接 CameraManager 方法) | - -**ChaoFengFloatController 配置**: - -| 字段 | 值 | -|-----|---| -| `_floatHeight` | 悬空高度(米,策划填写) | -| `_riseDuration` | 上浮时长(推荐约 1.5 秒) | -| `_fallDuration` | 落下时长(推荐约 0.8 秒) | -| `_rb` | 拖入根节点 Rigidbody2D | - -**ChaoFengKnockdownCounter 配置**: - -| 字段 | 值 | -|-----|---| -| `_threshold` | 击落所需命中次数(策划填写,推荐 8) | -| `_boss` | 拖入根节点 ChaoFengBoss 组件 | -| `_floatCtrl` | 拖入根节点 ChaoFengFloatController 组件 | -| `_knockdownHitClip` | `KnockdownHit.anim` | -| `_staggerClip` | `Stagger.anim`(与 Defeat_Pant 可共用同一 Clip) | -| `_staggerDuration` | `3`(落地硬直时长,策划调整) | - -**BossBase 相关配置(EnemyBase 父类)**: -- `_stats`:`ENM_ChaoFeng_Stats.asset` -- 在 `BossSkillExecutor` 组件中,添加所有 5 个 BossSkillSO(Boomerang/FanCombo/TornadoSmall/TornadoLarge/WindStone) - -### Step 5:搭建嘲风行为树 - -> ⚠️ **重要**:嘲风只有**一棵**行为树,不要为 Phase 1 和 Phase 2 创建两棵树。 - -``` -Selector [嘲风根节点] -│ -├── Sequence [Phase 2 (HP < 50%)] -│ ├── BD_IsHPBelow → ratio: 0.5 -│ ├── BD_BossPhaseTransition → targetPhase: 1, invincibleDuration: 2.0 -│ │ (约 1.5s 上浮 + 0.5s 缓冲;过渡中无敌;完成后 CurrentPhase=1) -│ └── Selector [Phase 2 战斗] -│ ├── BD_UseBossSkillWeighted ← 仅 wind_stone(availablePhaseIndices=[1]) -│ └── BD_Wait → Duration: 0.5 -│ -└── Selector [Phase 1 地面战斗] ← HP > 50% 时走此分支 - ├── BD_UseBossSkillWeighted ← 4 个 Phase 0 技能加权随机 - └── BD_MoveToPlayer -``` - -> ⚠️ **关键架构说明**: -> - `BD_BossPhaseTransition` 必须位于 Phase 2 Sequence 的**中间**,而非独立的并列节点。 -> - 过渡完成后(`CurrentPhase>=1`),`BD_BossPhaseTransition` 每 tick 立即返回 Success,Sequence 继续执行下方的战斗节点。 -> - 若两者为并列节点,过渡完成后父 Selector 只要第一个节点成功就停止,永远不会执行战斗节点。 - -> ⚠️ `BD_BossPhaseTransition.invincibleDuration` 必须 **≥ `_riseDuration` + 缓冲**(推荐 2.0 秒)。 -> 上浮动画在无敌期开始时立即播放,确保浮空完成后无敌期才结束。 - -### 回旋扇 AnimationEvent 设置 - -1. 打开 `Boomerang.anim` -2. 在发射时机帧添加 AnimationEvent -3. 函数名:`SpawnProjectile`,字符串参数:`"boomerang"` - -### 其他技能 AnimationEvent 设置 - -| 技能动画 | AnimationEvent 参数 | -|--------|-------------------| -| 小龙卷 | `SpawnProjectile("tornado_small")` | -| 大龙卷 | `SpawnProjectile("tornado_large")` | -| 风石 | `SpawnProjectile("wind_stone")` | - -### Step 6:Addressables - -- Address:`ENM_ChaoFeng` · Group:`Boss_ChaoFeng` · Labels:不加 Enemy 标签 - ---- - -## 11. Addressables 注册步骤 - -1. 打开 `Window → Asset Management → Addressables → Groups` -2. 找到对应 Group(Enemies / Boss_ChaoFeng / Projectiles) -3. 将 Prefab 拖入对应 Group -4. 在 Address 字段填入规范名称(如 `ENM_YouZhi`) -5. 在 Labels 栏勾选对应标签 -6. 点击 `Build → New Build → Default Build Script` 更新资产 - -**Addressables 汇总表**: - -| Address | Group | Labels | -|---------|-------|--------| -| `ENM_CaoZhi` | Enemies | Enemy | -| `ENM_HuangZhi` | Enemies | Enemy | -| `ENM_YouZhi` | Enemies | Enemy, Poolable, Preload | -| `ENM_ZhiMu` | Enemies | Enemy | -| `ENM_FeiZhi` | Enemies | Enemy | -| `ENM_Huan` | Enemies | Enemy | -| `ENM_ChaoFeng` | Boss_ChaoFeng | — | -| `PROJ_Boomerang` | Projectiles | Poolable, Preload | -| `PROJ_ZhiMu_Acid` | Projectiles | Poolable, Preload | -| `PROJ_FeiZhi_Acid` | Projectiles | Poolable, Preload | -| `PROJ_TornadoSmall` | Projectiles | Poolable, Preload | -| `PROJ_TornadoLarge` | Projectiles | Poolable, Preload | -| `PROJ_WindStone` | Projectiles | Poolable, Preload | - ---- - -## 12. 常见错误排查 - -### ❌ 技能触发后动画不播放 - -**原因**:能力 SO(EnemyAbilitySO)的 `attackSequence` 中 `clip` 字段未绑定 Clip,或 Ability 组件上的 `ClipTransition` 字段未绑定。 -**修复**:检查 Inspector,确认所有 `ClipTransition` 字段已拖入对应 `.anim` 文件。 - ---- - -### ❌ BD_UseAbility 没有效果(技能没有执行) - -**原因 A**:Ability 组件没有挂在子节点,而是挂在根节点本身。 -**修复**:将 Ability 组件移到 `Abilities/` 子节点。 - -**原因 B**:`abilityId` 与 SO 中的 `abilityId` 不一致(大小写或拼写错误)。 -**修复**:对照 SO 的 `abilityId` 字段,确认拼写完全一致。 - ---- - -### ❌ E003 出现后不下落 - -**原因 A**:`AnimatedCeilingDropAbility._groundMask` 未设置,导致落地检测失败,能力超时后强制结束。 -**修复**:将 Ground Layer 加入 `_groundMask`。 - -**原因 B**:`EnemyAbilityTrigger._executeOnSpawn` 未勾选(对象池路径无法触发下落),或 `_abilityId` 与 `ABL_E003_Fall.asset` 的 `abilityId`(`e003_fall`)不一致。 -**修复**:在 Inspector 勾选 `_executeOnSpawn` 并确认 `_abilityId` 拼写正确。 - ---- - -### ❌ E005 死亡后没有生成 E003 - -**原因 A**:`Death_Pre.anim` 中没有 AnimationEvent,或函数名/参数拼写错误。 -**修复**:打开动画编辑器,确认 AnimationEvent 的函数为 `SpawnProjectile`,参数为 `"spawn_e003"`(区分大小写),且与 `EnemySpawnerOnEvent._payloadKey` 一致。 - -**原因 B**:`EnemySpawnerOnEvent._poolKey` 拼写错误,或 `ENM_YouZhi` 未注册到 Addressables。 -**修复**:确认 Addressable Address、对象池 Pool Key 与 `EnemySpawnerOnEvent._poolKey` 均为 `ENM_YouZhi`(完全一致)。 - ---- - -### ❌ E004 Flip 动画不触发 - -**原因**:`ABL_E004_Flip` 的条件由 `FacePlayerAbility.CanUse` 内置检测(无其他技能运行 + 玩家在背后),不需要在行为树里额外检测。 -**验证**:打开 Runtime 调试,确认 `FacePlayerAbility.CanUse` 返回 true。常见失效原因是另一个技能仍在执行(`IsRunning=true`)。 - ---- - -### ❌ 嘲风 Phase 2 只执行一次过渡,之后不战斗 - -**原因**:`BD_BossPhaseTransition` 节点被放在独立的并列 Selector 下,而不是内嵌在 Phase 2 Sequence 中间。 -**修复**:参照本文档 §10 的行为树结构,确认 `BD_BossPhaseTransition` 是 Phase 2 Sequence 的中间节点,之后跟着战斗 Selector。 - ---- - -### ❌ 嘲风上浮后动画还是地面状态 - -**原因**:`BD_BossPhaseTransition.invincibleDuration` 设置过短,浮空还没完成无敌期就结束了,后续被 BT 打断。 -**修复**:将 `invincibleDuration` 设为 **≥ `_riseDuration` + 0.5 缓冲**(推荐 2.0 秒)。 - ---- - -### ❌ 回旋扇飞出后不回来 - -**原因 A**:`ReturnProjectile.SetOwner()` 没有被调用,`_ownerTransform` 为 null。 -**验证**:确认 `ChaoFengBoss.SpawnProjectile("boomerang")` 中调用了 `go.GetComponent()?.SetOwner(transform)`。这是 C# 代码,程序检查,策划确认 AnimationEvent 的 payload 拼写正确(`"boomerang"` 全小写)。 - -**原因 B**:`PROJ_Boomerang` 的 Prefab 根节点没有挂 `PooledObject` 组件。 -**修复**:添加 `PooledObject` 组件。 - ---- - -> 如遇到本文档未涵盖的问题,请联系程序查看 `Docs/Plan/小怪与Boss实现计划-01.md` 中的架构关键约束章节,或查阅 `Docs/Architecture/07_EnemyModule.md`。 diff --git a/Docs/Guides/08_BehaviorTree_Authoring_Guide.md b/Docs/Guides/08_BehaviorTree_Authoring_Guide.md deleted file mode 100644 index a024f78d..00000000 --- a/Docs/Guides/08_BehaviorTree_Authoring_Guide.md +++ /dev/null @@ -1,200 +0,0 @@ -# 行为树创建指南 — 敌人 / Boss(Behavior Designer Pro) - -> 面向:在已用脚手架搭好的敌人/Boss Prefab 上,挂载并搭建行为树(BT),跑通「巡逻 → 感知 → 技能」闭环。 -> 配套:《小怪与Boss实现计划-01》(每个敌人的目标 BT 结构)、`02_Enemy_Boss_Setup_Guide`。 - ---- - -## 0. 技术栈与前提 - -| 项 | 说明 | -|----|------| -| 行为树框架 | **Opsive Behavior Designer Pro**(`com.opsive.behaviordesigner`,运行时组件 `Opsive.BehaviorDesigner.Runtime.BehaviorTree`) | -| 编辑器入口 | `Tools/Opsive/Behavior Designer`;或选中带 `BehaviorTree` 组件的对象,在 Inspector 点 **Open** | -| 自定义任务 | `Assets/_Game/Scripts/Enemies/AI/BD_*.cs`,分类前缀 `BaseGames/Enemy/*` | -| 编译宏 | 全部 BD_ 任务用 `#if GRAPH_DESIGNER` 门控。**已在 ProjectSettings → Standalone 定义 `GRAPH_DESIGNER`**。换其它构建目标需自行补该宏,否则任务不可见。 | - -**前提**:敌人/Boss Prefab 已由 `SceneObjectPlacerTool` 脚手架生成,已具备 `EnemyBase`/`EnemyMovement`/`PhysicsPerceptionSystem`/`HurtBox`/`HitBox`/`Abilities/*` 与绑定好的 SO。BT 只负责**决策与调用**,不负责动画、不负责具体攻击实现。 - ---- - -## 1. 三条铁律(搭树前必读) - -1. **动画所有权**:所有技能/触发型动画由对应 `EnemyAbilityBase` 子类在 `ExecuteCoroutine()` 内 `_animancer.Play()` 播放。**BT 禁止用 `BD_PlayAnimation` 触发技能动画**。Idle/Walk/Run/Dead 由框架随 `SetAiPhase` / `Die()` 自动播放。 -2. **能力按 abilityId 调用**:`BD_UseAbility` / `BD_CanUseAbility` / `BD_IsAbilityRunning` 通过 abilityId(或 SO 引用)查找挂在 `Abilities/` 子节点上的能力组件。abilityId 必须全局唯一。 -3. **墙/崖不走感知**:`BD_Patrol` 用 `EnemyMovement.IsWallAhead/IsLedgeAhead` 内置射线翻转,**无需感知槽**。感知槽只用于「发现玩家/攻击距离」等(见 §3)。 - ---- - -## 2. 创建一棵行为树(通用步骤) - -1. **挂组件**:选中敌人 Prefab 根对象 → `Add Component` → `Behavior Tree`(Opsive)。 -2. **打开编辑器**:Inspector 里点 **Open**(或 `Tools/Opsive/Behavior Designer`)。 -3. **保存形式**: - - **内联**(推荐单怪专用树):直接在该 Prefab 的 BehaviorTree 组件上编辑,随 Prefab 保存。 - - **共享图**(多怪复用):在编辑器中保存为独立 Behavior Tree 资产,再在组件上引用。约定路径 `Assets/_Game/Data/AI/BT_{敌人}.asset`,命名 `BT_*`。 -4. **搭树**:根用 **Selector**(见 §4 各结构),从任务面板(分类 `BaseGames/Enemy/*`)拖入 BD_ 任务,连边、填字段。 -5. **填字段**:`BD_IsAiPhase` 选枚举;`BD_UseAbility`/`BD_CanUseAbility` 填 abilityId 或拖 ABL SO;`BD_IsSensorDetecting` 填槽名(见 §3)。 -6. **保存** Prefab / 图资产。进入 Play 验证(§6)。 - -> ⚠️ **运行前确认**:该 Prefab 的 `EnemyBase._statsSO`/`_animConfig`、各能力 `_config`、感知 `_slots` 均已绑定(脚手架已做)。BT 只是调度层。 - ---- - -## 3. 感知槽位(`SensorSlotNames`) - -`BD_IsSensorDetecting.m_SlotName` 必须等于 `PhysicsPerceptionSystem` 上配置的槽名,常量定义于 `Assets/_Game/Scripts/Enemies/Perception/SensorSlotNames.cs`: - -| 常量 | 字符串 | 类型 | 典型用途 | -|------|--------|------|---------| -| `Aggro` | `aggro` | RangeCircle | 主警戒/追击范围 | -| `Alert` | `alert` | RangeCircle | 警觉(比 aggro 小) | -| `AttackMelee` | `attack_melee` | RangeCircle | 近战触发距离 | -| `AttackRange` | `attack_range` | RangeCircle/BoxCast | 远程/区域触发(E002 用正下方 BoxCast) | -| `Patrol` | `patrol` | RangeCircle | 巡逻范围限制 | -| `LOS` | `los` | BatchLOS | 无遮挡视线 | -| `Sight` | `sight` | Sight | 视锥 + 遮挡("看见玩家",E004/E006/嘲风用) | - -`m_AnyTarget=false` 时对 `EnemyBase.PlayerTransform` 判定;`true` 时用 `HasAnyDetection`(任意目标)。 - ---- - -## 4. 各敌人/Boss 的目标树结构 - -> 节点缩进表示父子;`Selector` 选择器(命中即返回),`Sequence` 顺序(全成功才成功)。 -> abilityId 已随脚手架生成(见 §5 速查)。`BD_CanUseAbility` 勾 `m_CheckRange=true` 时按 ABL SO 的 preferredMin/MaxRange 校验距离。 - -### E001 草蛭(伪装→激活追击→失感知收招→巡逻) -``` -Selector -├── Sequence [死亡] : BD_IsStateMatch(Dead) → BD_StopMovement -├── Sequence [激活] -│ ├── Selector [可激活]: BD_IsAiPhase(Idle) | BD_IsAiPhase(Patrol) -│ ├── BD_IsSensorDetecting("aggro") -│ ├── BD_UseAbility("e001_alert") // PlayClipAbility:播激活动画 -│ └── BD_SetAiPhase(Chase) -├── Sequence [追击] -│ ├── BD_IsAiPhase(Chase) -│ └── BD_UseAbility("e001_chase") // ContactChaseAbility:循环追击,失感知内部 SetAiPhase(Patrol) -└── Selector [巡逻] // ⚠ 必须 Selector - ├── Sequence [待机]: BD_IsAiPhase(Idle) → BD_WaitRandom(min,max) - └── Sequence [巡逻]: BD_IsAiPhase(Patrol) → BD_Patrol -``` - -### E002 簧蛭(固定陷阱:下方检测→钻出三段+脆弱窗口) -``` -Selector -├── Sequence [死亡]: BD_IsStateMatch(Dead) → BD_Wait(999) -└── Sequence - ├── BD_IsSensorDetecting("attack_range") // 正下方 BoxCast - ├── BD_CanUseAbility("e002_ceiling_strike") - └── BD_UseAbility("e002_ceiling_strike") // CeilingHangStrikeAbility:出击→脆弱悬挂→收回 -``` - -### E003 幼蛭(天花板落下→感知追击→兜底巡逻) -``` -Selector -├── Sequence [死亡]: BD_IsStateMatch(Dead) → BD_StopMovement -├── Sequence [下落一次]: BD_IsAiPhase(Idle) → BD_UseAbility("e003_fall") // AnimatedCeilingDropAbility 落地后内部 SetAiPhase(Patrol) -├── Sequence [追击]: BD_IsSensorDetecting("aggro") → BD_ChasePlayer -└── BD_Patrol -``` -> 预置于天花板的 E003 由场景战斗触发器调用 `EnemyAbilityTrigger.Trigger()`;由 E005 死亡生成的(对象池路径)经 `_executeOnSpawn` 在出生时自动触发,均执行 `e003_fall` 能力。 - -### E004 蛭母(出场→战斗循环:Flip/撕咬/头槌/酸液/靠近) -``` -Selector -├── Sequence [死亡]: BD_IsStateMatch(Dead) → BD_StopMovement -├── Sequence [出场一次]: BD_IsAiPhase(Idle) → BD_UseAbility("e004_appear") // AppearAbility 内部 SetAiPhase(Combat) -├── Sequence [战斗] -│ ├── BD_IsAiPhase(Combat) -│ └── Selector -│ ├── Sequence [Flip]: BD_CanUseAbility("e004_flip") → BD_UseAbility("e004_flip") // CanUse 内含"无其他技能+玩家在背后" -│ ├── Sequence [撕咬]: BD_CanUseAbility("e004_bite", CheckRange) → BD_UseAbility("e004_bite") -│ ├── Sequence [头槌]: BD_CanUseAbility("e004_headslam", CheckRange) → BD_UseAbility("e004_headslam") -│ ├── Sequence [酸液]: BD_CanUseAbility("e004_acid") → BD_UseAbility("e004_acid") -│ └── BD_MoveToPlayer -└── BD_MoveToPlayer -``` - -### E005 肥蛭(近撕咬+后摇脆弱 / 远酸液 / 追击;死亡生成 E003) -``` -Selector -├── Sequence [死亡]: BD_IsStateMatch(Dead) → BD_StopMovement // 死亡生成 E003 由 EnemySpawnerOnEvent(SpawnProjectile 动画事件路由)处理,不走 BT -├── Sequence [撕咬]: BD_CanUseAbility("e005_bite", CheckRange) → BD_UseAbility("e005_bite") -├── Sequence [酸液]: BD_CanUseAbility("e005_acid") → BD_UseAbility("e005_acid") -└── BD_ChasePlayer -``` - -### E006 讙(视锥感知→跳跃爪击 / 巡逻) -``` -Selector -├── Sequence [死亡]: BD_IsStateMatch(Dead) → BD_StopMovement -├── Sequence [跳跃攻击] -│ ├── BD_IsSensorDetecting("sight") // 正面视锥 -│ ├── BD_CanUseAbility("e006_leap") -│ └── BD_UseAbility("e006_leap") // LeapAttackAbility:Rigidbody 冲量 -└── BD_Patrol -``` - -### 嘲风 Boss(单棵树;Phase2 子树由 HP 守门,过渡节点内嵌) -``` -Selector [嘲风] -├── Sequence [Phase 2 (HP<50%)] -│ ├── BD_IsHPBelow(0.5) -│ ├── BD_BossPhaseTransition(targetPhase=1, invincibleDuration≈2.0) // 首次:Running→Success;之后守护即时 Success -│ └── Selector [Phase2 战斗] -│ ├── BD_UseBossSkillWeighted // 仅 wind_stone(availablePhaseIndices=[1]) -│ └── BD_Wait(0.5) -└── Selector [Phase 1 地面战] - ├── BD_UseBossSkillWeighted // boomerang/fan_combo/tornado_small/tornado_large(均 phase[0]) - └── BD_MoveToPlayer -``` -> - **不要**把「过渡」和「Phase2 战斗」做成并列兄弟节点——过渡完成后会永远停在第一个 Success 节点,进不去战斗。必须把 `BD_BossPhaseTransition` 作为 Phase2 Sequence 的**中间**节点。 -> - **击落机制不走 BT**:由 `ChaoFengKnockdownCounter`(经 `ChaoFengBoss.OnDamageTaken` 转发)独立驱动。 -> - 弹体经技能动画 `AnimationEvent → ChaoFengBoss.SpawnProjectile("boomerang"/"tornado_small"/"tornado_large"/"wind_stone")` 生成并按 ProjectileConfigSO 初始化。 - ---- - -## 5. abilityId / skillId 速查(脚手架已生成) - -| 敌人 | 能力组件 | abilityId | ABL 资产 | -|------|---------|-----------|---------| -| E001 | PlayClipAbility / ContactChaseAbility | `e001_alert` / `e001_chase` | `ABL_E001_Alert` / `ABL_E001_Chase` | -| E002 | CeilingHangStrikeAbility | `e002_ceiling_strike` | `ABL_E002_CeilingStrike` | -| E003 | AnimatedCeilingDropAbility | `e003_fall` | `ABL_E003_Fall` | -| E004 | Appear/Melee/RepeatSlam/Projectile/FacePlayer | `e004_appear`/`e004_bite`/`e004_headslam`/`e004_acid`/`e004_flip` | `ABL_E004_*` | -| E005 | Melee(后摇脆弱)/Projectile | `e005_bite` / `e005_acid` | `ABL_E005_*` | -| E006 | LeapAttack / ContactChase | `e006_leap` / `e006_chase` | `ABL_E006_*` | - -嘲风 BossSkillSO(`BD_UseBossSkill`/`BD_UseBossSkillWeighted` 用 skillId): -`boomerang` / `fan_combo` / `tornado_small` / `tornado_large`(Phase0)、`wind_stone`(Phase1)。 - ---- - -## 6. 验证 - -1. 把敌人放进可玩场景(脚手架的 `Place E00X`,或拖 Prefab);确保场景有 `NavSurface` 已烘焙(追击/MoveTo 依赖)。 -2. 进入 Play。在 Inspector 看 `EnemyBase` 的 `AiPhase` 是否随逻辑切换(Idle→Chase→Patrol…)。 -3. Scene 视图开 Gizmo:`PhysicsPerceptionSystem` 各槽以语义色绘制(aggro 橙 / sight 浅蓝 / attack_* 红粉…),确认范围与玩家触发一致。 -4. Behavior Designer 编辑器在 Play 时高亮当前执行节点,逐节点排查卡点。 - ---- - -## 7. 常见坑 - -| 现象 | 原因 / 解法 | -|------|------------| -| 巡逻分支用 Sequence 导致待机后不巡逻 | 巡逻必须用 **Selector**(待机/巡逻互斥分支) | -| `BD_UseAbility` 立刻返回成功、技能没播完 | 它会等 `IsRunning==false`;确认能力 `ExecuteCoroutine` 正确设置 `Phase`。技能不打断需 ABL SO `interruptOnHurt=false` | -| 攻击不触发 | `BD_CanUseAbility` 未勾 `m_CheckRange` 或 ABL 的 preferredRange/cooldown 不当;或感知槽名拼错(须用 `SensorSlotNames` 常量值) | -| 找不到 BD_ 任务 | 未定义 `GRAPH_DESIGNER`(当前仅 Standalone 已定义) | -| 嘲风进不了 Phase2 战斗 | 过渡节点做成了兄弟节点;须内嵌进 Phase2 Sequence(见 §4) | -| E002/固定怪 BT 里写了 Patrol/MoveTo | 固定陷阱无移动,不要加移动节点 | -| 翻身/墙崖检测想用感知槽 | 不需要;`BD_Patrol` 内置 `EnemyMovement.IsWallAhead/IsLedgeAhead` | - ---- - -## 8. 小结 - -行为树 = **条件判断(BD_IsXxx / BD_IsSensorDetecting)+ 调用(BD_UseAbility / BD_SetAiPhase / BD_UseBossSkill*)**。动画、攻击实现、感知计算、移动物理都在框架其它层;BT 保持「薄」。按 §4 的结构逐怪搭建,用 §5 的 id、§3 的槽名填字段,再按 §6 验证即可。