Files
zeling_v2/Docs/Design/06_EnemySystem.md
2026-05-08 11:04:00 +08:00

411 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 06 · 敌人系统
> **命名空间** `BaseGames.Enemies` · `BaseGames.Enemies.AI` · `BaseGames.Enemies.Navigation`
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **依赖** `BaseGames.Combat` · Behavior Designer Pro · PathBerserker2d
---
## 目录
1. [系统总览](#1-系统总览)
2. [EnemyBase — 敌人基础组件](#2-enemybase--敌人基础组件)
3. [EnemyStatsSO — 敌人属性配置](#3-enemystatsso--敌人属性配置)
4. [敌人状态机](#4-敌人状态机)
5. [Behavior Designer 任务目录](#5-behavior-designer-任务目录)
6. [标准行为树模板](#6-标准行为树模板)
7. [Boss 行为树模板](#7-boss-行为树模板)
8. [PathBerserker2d 导航集成](#8-pathberserker2d-导航集成)
9. [BossBase — Boss 特化设计](#9-bossbase--boss-特化设计)
10. [敌人 Prefab 层级结构](#10-敌人-prefab-层级结构)
11. [EnemyAnimationConfigSO](#11-enemyanimationconfigso)
12. [编辑器友好设计](#12-编辑器友好设计)
---
## 1. 系统总览
敌人系统由三个层次组成:
```
EnemyBaseMonoBehaviour协调器
├── EnemyStats ← 运行时属性HP、防御等
├── EnemyMovement ← Rigidbody2D 移动封装
├── EnemyAnimator ← Animancer 动画(单层)
├── EnemyCombat ← HitBox 管理
├── EnemyNavAgent ← PathBerserker2d 寻路封装
└── BehaviorTree ← Behavior Designer 行为树AI 决策)
组件关系:
BehaviorTreeWhat to do → EnemyBase接口 → EnemyMovement/EnemyCombat/EnemyNavAgentHow to do it
BD 任务通过 SharedVariable 访问 EnemyBase 接口,不直接操作 Rigidbody2D
```
---
## 2. EnemyBase — 敌人基础组件
`EnemyBase` 是所有敌人的基础,暴露给 BD 任务的**接口列表**
### 移动接口
| 方法 | 调用方BD任务 | 说明 |
|------|---------------|------|
| `MoveTo(Vector2 target)` | `BD_MoveTo` | 通过 NavAgent 移动到目标点 |
| `MoveInDirection(float dir)` | `BD_Patrol` | 直接控制水平移动方向(无寻路)|
| `StopMovement()` | `BD_StopMovement` | 立即停止移动 |
| `JumpTo(Vector2 target)` | `BD_Jump` | 施加跳跃冲量朝向目标 |
| `Knockback(DamageInfo)` | HurtBox | 受击击退(不由 BD 控制)|
| `FacePlayer()` | `BD_FaceTarget` | 翻转 SpriteRenderer 朝向玩家 |
### 战斗接口
| 方法 | 调用方BD任务| 说明 |
|------|--------------|------|
| `BeginAttack(AttackType type)` | `BD_Attack` | 开始攻击(激活对应 HitBox|
| `CanAttack()` | `BD_CanAttack` | 检查攻击是否冷却完毕 |
| `IsPlayerInRange(float range)` | `BD_IsInRange` | 检测玩家是否在攻击范围内 |
| `IsPlayerVisible()` | `BD_IsVisible` | Raycast 检测玩家是否可见 |
### 状态接口
| 方法/属性 | 说明 |
|----------|------|
| `ForceState(EnemyStateType)` | 强制切换敌人状态Stagger/Death 等)|
| `TakeDamage(DamageInfo)` | 接受伤害(由 HurtBox 调用)|
| `IsDead` | 是否已死亡(只读)|
| `IsStaggered` | 是否处于硬直中(只读)|
| `CurrentHP` | 当前 HP只读供 BD Conditional 使用)|
---
## 3. EnemyStatsSO — 敌人属性配置
`EnemyStatsSO` 继承自 `ScriptableObject`,每类敌人一份资产:
| 字段 | 类型 | 说明 |
|------|------|------|
| `DisplayName` | `string` | 敌人名称UI显示|
| `MaxHP` | `int` | 最大生命值 |
| `DefenseStat` | `int` | 防御减免值 |
| `WalkSpeed` | `float` | 行走速度 |
| `RunSpeed` | `float` | 追击速度 |
| `DetectionRange` | `float` | 玩家检测半径 |
| `AttackRange` | `float` | 攻击触发范围 |
| `AttackCooldown` | `float` | 攻击冷却时间 |
| `GeoDropAmount` | `int` | 死亡时掉落 Geo |
| `GeoDropVariance` | `int` | Geo 掉落随机浮动量 |
| `StaggerResistance` | `float` | Stagger 抗性0=正常1=免疫)|
| `PatrolDistance` | `float` | 巡逻范围(从出生点起)|
### 资产存放路径
`Assets/ScriptableObjects/Enemies/Stats/`
命名规范:`ES_{EnemyName}.asset`,如 `ES_GruntWarrior.asset``ES_SkullArcher.asset`
---
## 4. 敌人状态机
`EnemyBase` 内部维护轻量状态枚举(不使用 Animancer FSMBD 行为树处理大部分逻辑):
| 状态 | 说明 | 优先级 |
|------|------|--------|
| `Dead` | 已死亡,所有系统停用 | 最高 |
| `Stagger` | 弹反/强击后硬直 | 90 |
| `Hurt` | 受击硬直 | 80 |
| `Controlled` | BD 行为树正常控制 | 10 |
`EnemyBase.State != Controlled`BehaviorTree 暂停执行(调用 `BehaviorTree.DisableBehavior()`)。
---
## 5. Behavior Designer 任务目录
### Action Tasks
| 任务类名 | 命名空间 | 说明 |
|---------|---------|------|
| `BD_MoveTo` | `BaseGames.Enemies.AI` | 通过 NavAgent 移动到 `SharedTransform target` |
| `BD_MoveToPlayer` | `BaseGames.Enemies.AI` | 持续追踪玩家位置 |
| `BD_Patrol` | `BaseGames.Enemies.AI` | 在巡逻区间来回移动(非寻路,直接控制速度)|
| `BD_FacePlayer` | `BaseGames.Enemies.AI` | 翻转 Sprite 朝向玩家 |
| `BD_Wait` | `BaseGames.Enemies.AI` | 等待 `SharedFloat duration` 秒(`Success` 后)|
| `BD_WaitRandom` | `BaseGames.Enemies.AI` | 随机等待 min~max 秒 |
| `BD_Attack` | `BaseGames.Enemies.AI` | 执行攻击(激活 HitBox播放攻击动画|
| `BD_PlayAnimation` | `BaseGames.Enemies.AI` | 播放指定 AnimancerState |
| `BD_StopMovement` | `BaseGames.Enemies.AI` | 立即停止移动 |
| `BD_SetAlert` | `BaseGames.Enemies.AI` | 设置 SharedBool `isAlerted` 为 true触发警觉动画 |
| `BD_SpawnProjectile` | `BaseGames.Enemies.AI` | 从挂载点生成弹射物 |
| `BD_TeleportTo` | `BaseGames.Enemies.AI` | 瞬移到指定位置Boss 特殊移动)|
### Conditional Tasks
| 任务类名 | 说明 | 返回值 |
|---------|------|--------|
| `BD_IsPlayerInRange` | 玩家是否在攻击范围内 | `Success` / `Failure` |
| `BD_IsPlayerVisible` | Raycast 检测玩家可见性 | `Success` / `Failure` |
| `BD_CanAttack` | 攻击是否冷却完毕 | `Success` / `Failure` |
| `BD_IsHPBelow` | HP 是否低于阈值(`SharedFloat threshold`| `Success` / `Failure` |
| `BD_IsPlayerOnSamePlatform` | 玩家是否在同一平台上 | `Success` / `Failure` |
| `BD_IsPatrolComplete` | 巡逻是否到达端点 | `Success` / `Failure` |
| `BD_IsAlerted` | 是否处于警觉状态 | `Success` / `Failure` |
### BD SharedVariables 规范
所有 BD 行为树中使用的 SharedVariable 命名约定(保持所有敌人一致):
| 变量名 | 类型 | 说明 |
|--------|------|------|
| `playerTransform` | `SharedTransform` | 玩家 Transform由 EnemyBase 注入)|
| `selfTransform` | `SharedTransform` | 自身 Transform |
| `patrolPointA` | `SharedVector2` | 巡逻起点 |
| `patrolPointB` | `SharedVector2` | 巡逻终点 |
| `isAlerted` | `SharedBool` | 是否警觉 |
| `targetPosition` | `SharedVector2` | 当前寻路目标 |
| `hpThreshold` | `SharedFloat` | HP 百分比阈值Boss 换相用)|
---
## 6. 标准行为树模板
### 模板 A巡逻-警觉-追击-攻击(近战普通敌人)
```
[Selector]
├─ [Sequence] — 死亡检测(优先级最高)
│ └─ [Conditional] BD_IsHPBelow(0) → Running触发 Dead 状态BD 暂停)
├─ [Sequence] — 追击并攻击
│ ├─ [Conditional] BD_IsPlayerVisible
│ ├─ [Action] BD_FacePlayer
│ ├─ [Selector] — 攻击或追击
│ │ ├─ [Sequence] — 攻击
│ │ │ ├─ [Conditional] BD_IsPlayerInRange
│ │ │ ├─ [Conditional] BD_CanAttack
│ │ │ ├─ [Action] BD_StopMovement
│ │ │ └─ [Action] BD_Attack
│ │ └─ [Action] BD_MoveToPlayer — 追击
│ └─ [Action] BD_SetAlert
└─ [Sequence] — 巡逻
├─ [Action] BD_Patrol
└─ [Action] BD_WaitRandom(1.0, 2.5)
```
### 模板 B弓箭手远程攻击
```
[Selector]
├─ [Sequence] — 远程攻击
│ ├─ [Conditional] BD_IsPlayerVisible
│ ├─ [Action] BD_FacePlayer
│ ├─ [Action] BD_StopMovement
│ ├─ [Conditional] BD_CanAttack
│ └─ [Action] BD_SpawnProjectile
├─ [Sequence] — 保持距离
│ ├─ [Conditional] BD_IsPlayerInRange(3.0) ← 太近则后退
│ └─ [Action] BD_MoveInDirection(-1) ← 后退
└─ [Action] BD_Patrol
```
---
## 7. Boss 行为树模板
Boss 使用多阶段结构,`BD_IsHPBelow` 控制阶段切换:
```
[Selector]
├─ [Sequence] — 阶段二HP < 40%
│ ├─ [Conditional] BD_IsHPBelow(0.4)
│ └─ [Subtree] BossPhase2BehaviorTree
├─ [Sequence] — 阶段一(默认)
│ └─ [Subtree] BossPhase1BehaviorTree
└─ [Action] BD_Wait(99) ← 异常保底(不应到达)
```
**BossPhase1BehaviorTree子树**
```
[Selector]
├─ [Sequence] — 近距攻击
│ ├─ [Conditional] BD_IsPlayerInRange(2.5)
│ ├─ [Conditional] BD_CanAttack
│ └─ [Action] BD_Attack(AttackType.MeleeCombo)
├─ [Sequence] — 远程技能
│ ├─ [Conditional] BD_CanAttack
│ ├─ [Action] BD_StopMovement
│ └─ [Action] BD_Attack(AttackType.RangedSkill)
└─ [Action] BD_MoveToPlayer
```
---
## 8. PathBerserker2d 导航集成
`EnemyNavAgent` 是对 PathBerserker2d `NavAgent` 的封装,向 BD 任务提供简洁接口:
### NavSurface 场景配置
每个场景必须配置:
```
[NavMesh] (Scene Root GameObject)
├── NavSurface ← PathBerserker2d 导航面
│ ├── Layer Mask: Ground, Platform, OneWayPlatform
│ └── Agent Radius: 0.3(按最小敌人尺寸)
└── NavLink_Platform_01 ← 平台跳跃链接(手动放置)
NavLink_Platform_02
...
```
**NavSurface 烘焙时机**
- 编辑时(静态场景):在 Unity Editor 中提前烘焙并保存
- 运行时动态场景P1调用 `NavSurface.BuildNavMesh()` 动态重烘焙
### NavLink 类型规范
| NavLink 类型 | 使用场景 | 配置参数 |
|-------------|---------|---------|
| `Jump` | 从平台跳到下方平台 | `MaxFallHeight``JumpForce` |
| `DropDown` | 穿越单向平台下落 | `OneWayPlatformLayer` |
| `LedgeGrab` | 抓爬台阶P1| `ClimbHeight` |
### EnemyNavAgent 封装接口
| 方法 | 说明 |
|------|------|
| `RequestMoveTo(Vector2 dest)` | 请求寻路到目标,异步开始 |
| `StopNavigation()` | 停止寻路,清空路径 |
| `IsAtDestination()` | 是否到达目标点(误差 < 0.2 units|
| `OnNavPathFailed` | UnityEvent寻路失败时触发切换为直接追击|
**寻路失败容错**:若 `PathBerserker2d` 无法找到路径,`EnemyNavAgent.OnNavPathFailed` 触发BD 行为树退化为简单的水平追击(`BD_MoveInDirection`)。
---
## 9. BossBase — Boss 特化设计
`BossBase` 继承 `EnemyBase`,新增以下机制:
### BossPhaseConfigSO
每个 Boss 阶段独立 SO 资产,便于策划调整:
| 字段 | 类型 | 说明 |
|------|------|------|
| `PhaseIndex` | `int` | 阶段编号从1开始|
| `HPThreshold` | `float` | 进入此阶段的 HP 百分比0~1|
| `BehaviorTreeAsset` | `ExternalBehaviorTree` | 该阶段使用的 BD 行为树资产 |
| `MusicTrack` | `AudioClip` | 阶段背景音乐 |
| `PhaseTransitionFeedback` | `MMF_Player` | 换相时播放的 Feel 反馈(特效/震动)|
### 血量分段显示
`BossHPBar` 根据 `BossPhaseConfigSO[]` 绘制血量分段线,玩家可在 UI 中预判换相位置。
### BossArena 配置
```
[BossArena] (Scene GameObject)
├── ArenaCollider ← PolygonCollider2D限制玩家退出 Boss 房间
├── BossSpawnPoint ← Boss 出生点
├── [CameraBounds_Boss] ← 专属 Cinemachine Confiner固定大视野
└── BossRoomTrigger ← OnTriggerEnter2D 触发 Boss 战开始
└─ 发布 OnBossFightStarted 事件频道
```
---
## 10. 敌人 Prefab 层级结构
```
[Enemy_GruntWarrior] (Prefab)
├── SpriteRenderer
├── AnimancerComponent
├── Rigidbody2D (Body Type: Dynamic, Freeze Rotation Z)
├── CapsuleCollider2D (物理碰撞)
├── [HurtBox]
│ ├── BoxCollider2D (IsTrigger, Layer: EnemyHurtBox)
│ └── HurtBox.cs
├── [HitBox_Melee]
│ ├── BoxCollider2D (IsTrigger, Layer: EnemyAttack)
│ └── HitBox.cs
│ └── _damageSource: ES_GruntWarrior_Melee.asset
├── [DetectionRange]
│ └── CircleCollider2D (IsTrigger, 半径 = DetectionRange)
├── EnemyBase.cs
├── EnemyStats.cs ← 持有 EnemyStatsSO 引用
├── EnemyMovement.cs
├── EnemyAnimator.cs
├── EnemyCombat.cs
├── EnemyNavAgent.cs ← 持有 NavAgent 引用
├── BehaviorTree.cs ← 持有 BehaviorTreeAsset 引用
└── EnemyFeedback.cs ← 持有 MMF_Player 引用
```
---
## 11. EnemyAnimationConfigSO
每类敌人配置独立的 `EnemyAnimationConfigSO`(存放于 `Assets/ScriptableObjects/Enemies/Animations/`
| 字段名 | 说明 |
|--------|------|
| `Idle` | 待机循环动画 |
| `Walk` | 行走循环 |
| `Run` | 奔跑循环 |
| `Alert` | 警觉动画(发现玩家时)|
| `Attack_Melee` | 近战攻击 |
| `Attack_Ranged` | 远程攻击(弓箭手/法师)|
| `Hurt` | 受击动画 |
| `Stagger` | 弹反硬直 |
| `Death` | 死亡动画(播放一次后保持最后帧)|
---
## 12. 编辑器友好设计
### EnemyBase 自定义 Inspector
```
┌─ EnemyBase ─────────────────────────────────────┐
│ State : Controlled │
│ HP : █████████░░░ 75 / 100 │
│ Alerted : ✓ │
│ Nav Path : Active → Room_Forest_01 (0.8m) │
│ ───────────────────────────────────────────── │
│ BD Tree : [GruntWarrior_Patrol.asset] │
│ [当前执行节点: BD_MoveToPlayer] │
│ ───────────────────────────────────────────── │
│ [强制Stagger 0.8s] [强制Death] [重置HP] [重置BD]│
└─────────────────────────────────────────────────┘
```
### Scene 视图 Gizmos
| Gizmo | 颜色 | 说明 |
|-------|------|------|
| 检测范围 | 黄色圆圈 | `DetectionRange` 球形范围 |
| 攻击范围 | 红色圆圈 | `AttackRange` 球形范围 |
| 巡逻路径 | 蓝色线段 | `patrolPointA``patrolPointB` 连线 |
| 寻路目标 | 绿色箭头 | 指向当前 NavAgent 目标点 |
| HitBox | 橙色矩形 | 攻击判定区域(激活时实心,未激活时虚线)|
| HurtBox | 绿色矩形 | 受击区域 |
| 视线检测 | 青色射线 | `IsPlayerVisible` 使用的 Raycast |