411 lines
15 KiB
Markdown
411 lines
15 KiB
Markdown
# 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. 系统总览
|
||
|
||
敌人系统由三个层次组成:
|
||
|
||
```
|
||
EnemyBase(MonoBehaviour,协调器)
|
||
├── EnemyStats ← 运行时属性(HP、防御等)
|
||
├── EnemyMovement ← Rigidbody2D 移动封装
|
||
├── EnemyAnimator ← Animancer 动画(单层)
|
||
├── EnemyCombat ← HitBox 管理
|
||
├── EnemyNavAgent ← PathBerserker2d 寻路封装
|
||
└── BehaviorTree ← Behavior Designer 行为树(AI 决策)
|
||
|
||
组件关系:
|
||
BehaviorTree(What to do) → EnemyBase接口 → EnemyMovement/EnemyCombat/EnemyNavAgent(How 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 FSM,BD 行为树处理大部分逻辑):
|
||
|
||
| 状态 | 说明 | 优先级 |
|
||
|------|------|--------|
|
||
| `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 |
|