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

675 lines
24 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.
# 19 · Boss 攻击模式库Boss Pattern Library
> **命名空间** `BaseGames.Enemies.Boss.Patterns`
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **依赖** `BaseGames.Enemies` · `BaseGames.Combat` · `BaseGames.Feedback` · `BaseGames.Core.Events` · BehaviorDesigner · Animancer
---
## 目录
1. [系统总览](#1-系统总览)
2. [攻击模式数据层](#2-攻击模式数据层)
3. [BossOrchestrator — 运行时编排器](#3-bossorchestrator--运行时编排器)
4. [TelegraphSystem — 预警系统](#4-telegraphsystem--预警系统)
5. [阶段转换规则](#5-阶段转换规则)
6. [内置攻击模式类型](#6-内置攻击模式类型)
7. [Boss 原型模板](#7-boss-原型模板)
8. [BehaviorDesigner 集成](#8-behaviordesigner-集成)
9. [事件频道](#9-事件频道)
10. [编辑器工具](#10-编辑器工具)
---
## 1. 系统总览
Boss 攻击模式系统将 Boss 战的**决策**与**执行**分离:
```
Boss 模式系统职责:
├─ AttackPatternSO → 单个攻击的完整数据(前摇/活跃/后摇/伤害/移动/预警)
├─ BossPhaseConfigSO → 一个阶段的模式集合(权重、冷却、组合规则)
├─ BossOrchestrator → 运行时编排:选模式 → 执行 → 监听结果
├─ TelegraphSystem → 攻击前的视觉/音效预警Surface Marker、闪光、UI 箭头)
└─ PhaseTransitionRule → HP 阈值 → 触发阶段切换
```
**设计原则**
- `AttackPatternSO` 完全数据化,美术/策划可在 Inspector 中配置
- BehaviorDesigner 调用 `BossOrchestrator`**Action Task**,不直接操作动画
- 阶段切换通过 SO 事件频道广播,不在 BossBase 内硬编码
---
## 2. 攻击模式数据层
### AttackPatternSO — 单个攻击模式
```csharp
[CreateAssetMenu(menuName = "Enemies/Boss/AttackPattern")]
public class AttackPatternSO : ScriptableObject
{
[Header("基础信息")]
public string patternId; // 唯一 ID用于动画事件映射
public string displayName; // 编辑器显示名
[Header("时序(秒)")]
public float telegraphDuration; // 预警时长(玩家反应窗口)
public float windupDuration; // 前摇(动画加速,不可取消)
public float activeDuration; // 活跃帧HitBox 开启)
public float recoveryDuration; // 后摇(可被打断的脆弱期)
[Header("伤害")]
public DamageSourceSO damageSource; // 复用战斗系统的伤害描述 SO
public bool isParryable; // 是否可弹反
public KnockbackProfile knockback;
[Header("运动控制")]
public bool lockBossMovement; // 前摇/活跃期间锁定 Boss 移动
public AnimationCurve movementCurve; // Boss 位移曲线(空 = 不移动)
public float movementDistance; // 冲刺/位移距离
[Header("投射物")]
public ProjectileConfigSO[] projectiles; // 发射的弹射物(可多个)
public Vector2[] projectileDirections; // 对应发射方向
[Header("预警配置")]
public TelegraphConfig telegraph; // 预警类型及参数(见 §4
[Header("权重与冷却")]
[Range(1, 10)]
public int weight; // 选择权重(越高越常被选中)
public float cooldown; // 同一模式的最小复用间隔(秒)
[Header("条件")]
public PatternCondition[] activationConditions; // 激活条件(距离/玩家位置/HP范围
}
```
### PatternCondition — 激活条件
```csharp
[Serializable]
public struct PatternCondition
{
public ConditionType type;
// ── InRange ──
public float minRange;
public float maxRange;
// ── HPBelow / HPAbove ──
[Range(0f, 1f)] public float hpThreshold;
// ── PlayerIsAbove / PlayerIsBelow / PlayerIsBehind ──
// 无额外参数
}
public enum ConditionType
{
InRange, // 玩家在 [minRange, maxRange] 内
OutOfRange, // 玩家在 maxRange 外
HPBelow, // Boss HP < hpThreshold
HPAbove, // Boss HP > hpThreshold
PlayerIsAbove, // 玩家高于 Boss触发对空攻击
PlayerIsBelow, // 玩家低于 Boss触发下方攻击
PlayerIsBehind, // 玩家在 Boss 身后(触发转身攻击)
Always, // 无条件(默认)
}
```
### BossPhaseConfigSO — 阶段配置
```csharp
[CreateAssetMenu(menuName = "Enemies/Boss/PhaseConfig")]
public class BossPhaseConfigSO : ScriptableObject
{
[Header("阶段信息")]
public int phaseIndex; // 0 = 第一阶段
public string phaseName;
public Color phaseColor; // Boss HP 条颜色(用于区分阶段)
[Header("可用模式")]
public AttackPatternSO[] patterns;
[Header("休息间隔")]
public float minIdleGap; // 两次攻击之间最小空闲(秒)
public float maxIdleGap; // 两次攻击之间最大空闲(秒)
[Header("连招规则")]
public int maxComboCount; // 最多连续 n 次不同模式再强制休息
public bool allowRepeatPattern; // 是否允许同一模式连续出现
[Header("阶段过渡特效")]
public FeedbackPresetSO transitionFeedback; // 阶段切换时的 MMF_Player 预设
}
```
---
## 3. BossOrchestrator — 运行时编排器
`BossOrchestrator` 挂载于 BossBase 所在 GameObject负责模式选择与执行状态追踪。
```csharp
namespace BaseGames.Enemies.Boss.Patterns
{
public class BossOrchestrator : MonoBehaviour
{
[Header("配置")]
[SerializeField] BossPhaseConfigSO[] _phases; // 所有阶段配置,按 phaseIndex 排列
[SerializeField] TelegraphSystem _telegraph; // 预警组件
[Header("事件频道")]
[SerializeField] IntEventChannelSO _onBossPhaseChanged; // 发布(传入新阶段索引)
[SerializeField] VoidEventChannelSO _onBossVulnerable; // 后摇期间发布(玩家可追打提示)
[SerializeField] StringEventChannelSO _onPatternStarted; // 发布 patternId音频/镜头响应)
// ── 运行时状态 ──
BossPhaseConfigSO _currentPhase;
AttackPatternSO _currentPattern;
PatternState _state;
float _stateTimer;
int _comboCounter;
readonly Dictionary<AttackPatternSO, float> _cooldownTimers = new();
public bool IsExecutingPattern => _state != PatternState.Idle;
public AttackPatternSO CurrentPattern => _currentPattern;
// ────────────────────────────────────────────
// 公开 API供 BehaviorDesigner Tasks 调用)
// ────────────────────────────────────────────
public void SetPhase(int phaseIndex)
{
_currentPhase = _phases[phaseIndex];
_comboCounter = 0;
_onBossPhaseChanged.Raise(phaseIndex);
}
/// <summary>
/// 选择并开始执行一个合适的攻击模式。
/// 返回 false 时表示没有可用模式AI 应等待后重试)。
/// </summary>
public bool TryExecutePattern(Vector2 playerPosition)
{
if (_state != PatternState.Idle) return false;
var pattern = SelectPattern(playerPosition);
if (pattern == null) return false;
StartPattern(pattern);
return true;
}
public void AbortCurrentPattern()
{
StopAllCoroutines();
_state = PatternState.Idle;
_currentPattern = null;
}
// ────────────────────────────────────────────
// 内部逻辑
// ────────────────────────────────────────────
AttackPatternSO SelectPattern(Vector2 playerPos)
{
float distToPlayer = Vector2.Distance(transform.position, playerPos);
bool playerAbove = playerPos.y > transform.position.y + 0.5f;
// 1. 筛选:满足条件 + 冷却完毕
var candidates = new List<(AttackPatternSO pat, int weight)>();
foreach (var p in _currentPhase.patterns)
{
if (!IsCooledDown(p)) continue;
if (!CheckConditions(p, distToPlayer, playerAbove)) continue;
if (!_currentPhase.allowRepeatPattern && p == _currentPattern) continue;
candidates.Add((p, p.weight));
}
if (candidates.Count == 0) return null;
// 强制休息检查
if (_comboCounter >= _currentPhase.maxComboCount) return null;
// 2. 加权随机选择
int totalWeight = candidates.Sum(c => c.weight);
int roll = UnityEngine.Random.Range(0, totalWeight);
int accumulated = 0;
foreach (var (pat, w) in candidates)
{
accumulated += w;
if (roll < accumulated) return pat;
}
return candidates[^1].pat;
}
void StartPattern(AttackPatternSO pattern)
{
_currentPattern = pattern;
_state = PatternState.Telegraph;
_comboCounter++;
_cooldownTimers[pattern] = Time.time;
_onPatternStarted.Raise(pattern.patternId);
StartCoroutine(ExecutePatternRoutine(pattern));
}
IEnumerator ExecutePatternRoutine(AttackPatternSO p)
{
// ── 预警阶段 ──
_telegraph.ShowTelegraph(p.telegraph);
yield return new WaitForSeconds(p.telegraphDuration);
_telegraph.HideTelegraph();
// ── 前摇 ──
_state = PatternState.Windup;
yield return new WaitForSeconds(p.windupDuration);
// ── 活跃帧(动画事件触发 HitBox此处设移动曲线──
_state = PatternState.Active;
yield return new WaitForSeconds(p.activeDuration);
// ── 后摇(脆弱期)──
_state = PatternState.Recovery;
_onBossVulnerable.Raise();
yield return new WaitForSeconds(p.recoveryDuration);
// ── 完毕 ──
_state = PatternState.Idle;
_currentPattern = null;
}
bool IsCooledDown(AttackPatternSO p)
=> !_cooldownTimers.TryGetValue(p, out float last)
|| Time.time - last >= p.cooldown;
bool CheckConditions(AttackPatternSO p, float dist, bool playerAbove)
{
foreach (var cond in p.activationConditions)
{
if (!EvaluateCondition(cond, dist, playerAbove)) return false;
}
return true;
}
bool EvaluateCondition(PatternCondition c, float dist, bool playerAbove)
=> c.type switch
{
ConditionType.InRange => dist >= c.minRange && dist <= c.maxRange,
ConditionType.OutOfRange => dist > c.maxRange,
ConditionType.PlayerIsAbove => playerAbove,
ConditionType.PlayerIsBelow => !playerAbove,
_ => true,
};
void Update()
{
// 冷却定时器自然流逝cooldownTimers 存储的是开始时间,不需要手动递减)
}
}
public enum PatternState { Idle, Telegraph, Windup, Active, Recovery }
}
```
---
## 4. TelegraphSystem — 预警系统
Boss 攻击前通过多层视觉/音效预警给玩家反应时间。
```csharp
public class TelegraphSystem : MonoBehaviour
{
[Header("预警 Prefab")]
[SerializeField] SpriteRenderer _flashOverlay; // Boss 躯体 sprite 闪红
[SerializeField] GameObject _groundMarkerPrefab; // 地面危险标记AOE 落点)
[SerializeField] GameObject _directionArrowPrefab; // 方向预警箭头(冲刺)
[SerializeField] AudioEventSO _telegraphSFX; // 预警音效频道
public void ShowTelegraph(TelegraphConfig config)
{
switch (config.type)
{
case TelegraphType.BodyFlash:
StartCoroutine(FlashRoutine(config.flashColor, config.duration));
break;
case TelegraphType.GroundMarker:
SpawnGroundMarker(config.targetPosition, config.radius);
break;
case TelegraphType.DirectionArrow:
ShowDirectionArrow(config.direction);
break;
case TelegraphType.FullBodyGlow:
SetBodyGlow(config.glowColor, config.duration);
break;
}
_telegraphSFX?.Raise();
}
public void HideTelegraph()
{
_flashOverlay.color = Color.white;
// 隐藏所有活跃的地面标记 / 方向箭头
}
// ... 各预警类型实现
}
[Serializable]
public struct TelegraphConfig
{
public TelegraphType type;
public Color flashColor; // BodyFlash / FullBodyGlow 颜色
public float duration; // 闪烁/发光持续时长
public Vector2 targetPosition; // GroundMarker 目标位置
public float radius; // GroundMarker 半径
public Vector2 direction; // DirectionArrow 方向
}
public enum TelegraphType
{
None,
BodyFlash, // Boss 躯体快速变色闪烁
GroundMarker, // 地面出现危险区域标记(红色圆圈)
DirectionArrow, // 在 Boss 前方显示冲刺方向箭头
FullBodyGlow, // Boss 全身发光(强攻击专用,通常配合音效)
}
```
---
## 5. 阶段转换规则
```csharp
[CreateAssetMenu(menuName = "Enemies/Boss/PhaseTransitionRule")]
public class PhaseTransitionRuleSO : ScriptableObject
{
[Header("触发条件")]
[Range(0f, 1f)]
public float hpThreshold; // HP 降到此比例以下触发
[Header("目标阶段")]
public int targetPhaseIndex;
[Header("过渡演出")]
public float invincibilityDuration; // 过渡期间无敌时长Boss 播放嘲讽/变身动画)
public bool healPartial; // 是否恢复部分 HP如恢复至下一阶段起始 HP
[Range(0f, 1f)]
public float partialHealAmount; // 恢复到 HP 总量的 x%
}
```
**BossBase 集成**(在 `06_EnemySystem.md §5 BossBase` 中追加):
```csharp
// BossBase.cs — 扩展阶段切换逻辑
[SerializeField] PhaseTransitionRuleSO[] _transitionRules;
[SerializeField] BossOrchestrator _orchestrator;
protected override void OnHPChanged(int newHP)
{
float ratio = (float)newHP / _stats.maxHP;
foreach (var rule in _transitionRules)
{
if (ratio <= rule.hpThreshold && !_triggeredPhases.Contains(rule.targetPhaseIndex))
{
_triggeredPhases.Add(rule.targetPhaseIndex);
StartCoroutine(ExecutePhaseTransition(rule));
break;
}
}
}
IEnumerator ExecutePhaseTransition(PhaseTransitionRuleSO rule)
{
// 1. 进入无敌状态
SetInvincible(true);
_orchestrator.AbortCurrentPattern();
// 2. 播放过渡演出反馈MMF_Player: 画面震动 + 色彩分离)
_transitionFeedback?.PlayFeedbacks();
yield return new WaitForSeconds(rule.invincibilityDuration);
// 3. 切换阶段
_orchestrator.SetPhase(rule.targetPhaseIndex);
SetInvincible(false);
}
```
---
## 6. 内置攻击模式类型
### 6.1 近战冲刺MeleeLunge
```
Telegraph: DirectionArrow朝玩家方向箭头0.5s
Windup: 0.2s(下蹲姿势)
Active: 0.15sHitBox开启 + Rigidbody2D 沿 movementCurve 冲刺)
Recovery: 0.5s滑步停止Boss 转向玩家)
DamageType: Melee · Knockback: Medium
isParryable: ✓
推荐 weight: 4 · cooldown: 1.5s
```
### 6.2 投射物连射ProjectileVolley
```
Telegraph: BodyFlash橙色0.6s
Windup: 0.3s(举起武器蓄力)
Active: 0.8s(动画事件每 0.2s 生成一颗弹射物,共 3~5 颗)
Recovery: 0.4s
DamageType: Projectile · isParryable: ✓(弹射物可弹反)
推荐 weight: 3 · cooldown: 3s
```
### 6.3 范围打击AreaDenial
```
Telegraph: GroundMarker玩家脚下红圈0.8s
Windup: 0.4s(跳跃升空)
Active: 0.1s(砸地,生成范围 HitBox
Recovery: 0.6s(落地后摇)
DamageType: Melee · AoE · isParryable: ✗
推荐 weight: 2 · cooldown: 4s
条件: InRange(0, 4)
```
### 6.4 全屏横扫HorizontalSweep
```
Telegraph: FullBodyGlow红色1.0s
Windup: 0.5s
Active: 0.3s(持续横向 HitBox 覆盖全屏宽)
Recovery: 0.8sBoss 喘息)
DamageType: Melee · Heavy · isParryable: ✗
推荐 weight: 1 · cooldown: 8s
条件: HPBelow(0.4)(仅在第二阶段以下使用)
```
### 6.5 多段连击MultiHitCombo
```
Telegraph: BodyFlash白色0.3s
Windup: 0.1s
Active: 1.2s3次HitBox依次开启间隔0.3s,最后一击可弹反)
Recovery: 0.6s
DamageType: Melee · Light(1), Light(1), Medium(2)
isParryable: 第3击 ✓
推荐 weight: 5 · cooldown: 2s
```
---
## 7. Boss 原型模板
### 7.1 敏捷近战 BossAgileKnight
**设计核心**:高移动速度、多次冲刺、强调弹反互动。
```
阶段 1HP 100%~50%:
模式集: MeleeLunge(w4) · MultiHitCombo(w5) · ProjectileVolley(w2)
IdleGap: 0.8~1.5s · MaxCombo: 3
阶段 2HP 50%~0%:
模式集: MeleeLunge(w6, cooldown减半) · MultiHitCombo(w5) · HorizontalSweep(w2, 仅HP<30%)
IdleGap: 0.3~1.0s · MaxCombo: 4
过渡: 1.5s无敌 + MMF 色调变红 + 速度提升 1.4×
```
### 7.2 远程投射 BossSorcererBoss
**设计核心**与玩家保持距离、多种弹道类型、Arena 控制。
```
阶段 1HP 100%~60%:
模式集: ProjectileVolley(w5) · AreaDenial(w3)
条件: OutOfRange(5) 时强制使用 TeleportBehindPlayer 模式
IdleGap: 1.0~2.0s
阶段 2HP 60%~0%:
新增模式: HomingProjectileSpray(向玩家发射3颗追踪弹)
IdleGap: 0.6~1.5s
过渡: 传送至场地中央 + FullBodyGlow 2s + 特殊动画
```
### 7.3 巨型多阶段 BossColossalBoss
**设计核心**3个阶段、每阶段改变整体行为模式、标志性大招。
```
阶段 1HP 100%~70%:
模式集: GroundSlam · MeleeLunge
弱点部位: HurtBox 仅在头部
阶段 2HP 70%~35%:
新增模式: WallJump + AreaDenial组合Boss跳墙后俯冲
弱点部位: 头部 + 双手3个 HurtBox
阶段 3HP 35%~0%:
HorizontalSweep + ProjectileVolley 组合使用
IdleGap 减至 0.3s
背景音乐切换至最终阶段曲
弱点部位: 全身开放
```
---
## 8. BehaviorDesigner 集成
### 自定义 Action Tasks
```csharp
// AI/Actions/Boss/ExecutePatternAction.cs
[TaskCategory("Boss/Orchestrator")]
[TaskDescription("请求编排器执行一个攻击模式。成功 = 找到并开始了模式;失败 = 无可用模式(需等待)")]
public class ExecutePatternAction : Action
{
[RequiredField] public SharedGameObject bossGO;
[RequiredField] public SharedTransform playerTransform;
BossOrchestrator _orchestrator;
public override void OnStart()
=> _orchestrator = bossGO.Value.GetComponent<BossOrchestrator>();
public override TaskStatus OnUpdate()
{
if (_orchestrator.IsExecutingPattern)
return TaskStatus.Running;
bool started = _orchestrator.TryExecutePattern(playerTransform.Value.position);
return started ? TaskStatus.Running : TaskStatus.Failure;
}
}
// AI/Actions/Boss/SetBossPhaseAction.cs
[TaskCategory("Boss/Orchestrator")]
public class SetBossPhaseAction : Action
{
public SharedInt phaseIndex;
BossOrchestrator _orchestrator;
public override void OnStart()
{
_orchestrator = GetComponent<BossOrchestrator>();
_orchestrator.SetPhase(phaseIndex.Value);
}
public override TaskStatus OnUpdate() => TaskStatus.Success;
}
// AI/Conditions/Boss/IsPatternComplete.cs
[TaskCategory("Boss/Orchestrator")]
[TaskDescription("检查编排器是否已完成当前模式(处于 Idle 状态)")]
public class IsPatternComplete : Conditional
{
BossOrchestrator _orchestrator;
public override void OnStart()
=> _orchestrator = GetComponent<BossOrchestrator>();
public override TaskStatus OnUpdate()
=> _orchestrator.IsExecutingPattern ? TaskStatus.Failure : TaskStatus.Success;
}
```
### 典型 Boss 行为树结构
```
Boss BehaviorTree
└── Selector优先检查阶段切换再执行攻击
├── Sequence阶段切换检查
│ ├── Conditional: IsBossHPBelow(0.5) && !IsPhase2Active
│ └── Action: SetBossPhaseAction(phaseIndex=1)
└── Sequence攻击循环
├── Action: UpdatePlayerPosition (更新黑板变量)
├── Action: FacePlayer (转向玩家)
├── Selector执行攻击或等待
│ ├── Action: ExecutePatternAction尝试执行模式
│ └── Action: WaitRandom(0.3, 1.0)(无可用模式时等待)
└── Action: IsPatternComplete (等待模式完成再循环)
```
---
## 9. 事件频道
| 频道资产 | 类型 | 发布方 | 主要订阅方 |
|---------|------|--------|----------|
| `OnBossPhaseChanged.asset` | `IntEventChannelSO` | `BossOrchestrator` | `BGMController`(切音乐)、`BossHPBar`(切颜色)、`CameraStateController`(切镜头) |
| `OnBossVulnerable.asset` | `VoidEventChannelSO` | `BossOrchestrator` | `UIManager`(显示"追打!"提示)、`PlayerFeedback`(提示音效)|
| `OnBossPatternStarted.asset` | `StringEventChannelSO` | `BossOrchestrator` | `AudioManager`(模式专属音效)、`CameraStateController`(镜头跟踪模式) |
| `OnBossDefeated.asset` | `StringEventChannelSO` | `BossBase.OnDeath()` | `GameManager``ProgressionSystem``CutsceneManager` |
---
## 10. 编辑器工具
### BossPatternPreview — Inspector 实时预览
`AttackPatternSO` 自定义 Inspector 显示时序甘特图:
```
┌─ AttackPatternSO: MeleeLunge ──────────────────────────────┐
│ 时序(总计 1.35s: │
│ [预警████0.5s][前摇██0.2s][活跃█0.15s][后摇█████0.5s] │
│ ───────────────────────────────────────────────────── │
│ 伤害: 2 · 可弹反: ✓ · 权重: 4 · 冷却: 1.5s │
│ 条件: 无 │
│ ───────────────────────────────────────────────────── │
│ [在 Scene 中预览预警] [在 Game 视图模拟执行] │
└────────────────────────────────────────────────────────────┘
```
### BossPhaseFlowGraph — EditorWindow
`Tools > Zeling > Boss Phase Flow` 显示:
- 所有 Boss Prefab 的阶段节点图
- HP 阈值触发箭头
- 每个阶段的模式列表(权重可视化为饼图)
- 点击模式节点 → 跳转到对应 `AttackPatternSO`