15 KiB
06 · 敌人系统
命名空间
BaseGames.Enemies·BaseGames.Enemies.AI·BaseGames.Enemies.Navigation
所属文档集 ← 返回索引 · 总览
依赖BaseGames.Combat· Behavior Designer Pro · PathBerserker2d
目录
- 系统总览
- EnemyBase — 敌人基础组件
- EnemyStatsSO — 敌人属性配置
- 敌人状态机
- Behavior Designer 任务目录
- 标准行为树模板
- Boss 行为树模板
- PathBerserker2d 导航集成
- BossBase — Boss 特化设计
- 敌人 Prefab 层级结构
- EnemyAnimationConfigSO
- 编辑器友好设计
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 |