24 KiB
24 KiB
19 · Boss 攻击模式库(Boss Pattern Library)
命名空间
BaseGames.Enemies.Boss.Patterns
所属文档集 ← 返回索引 · 总览
依赖BaseGames.Enemies·BaseGames.Combat·BaseGames.Feedback·BaseGames.Core.Events· BehaviorDesigner · Animancer
目录
- 系统总览
- 攻击模式数据层
- BossOrchestrator — 运行时编排器
- TelegraphSystem — 预警系统
- 阶段转换规则
- 内置攻击模式类型
- Boss 原型模板
- BehaviorDesigner 集成
- 事件频道
- 编辑器工具
1. 系统总览
Boss 攻击模式系统将 Boss 战的决策与执行分离:
Boss 模式系统职责:
├─ AttackPatternSO → 单个攻击的完整数据(前摇/活跃/后摇/伤害/移动/预警)
├─ BossPhaseConfigSO → 一个阶段的模式集合(权重、冷却、组合规则)
├─ BossOrchestrator → 运行时编排:选模式 → 执行 → 监听结果
├─ TelegraphSystem → 攻击前的视觉/音效预警(Surface Marker、闪光、UI 箭头)
└─ PhaseTransitionRule → HP 阈值 → 触发阶段切换
设计原则:
AttackPatternSO完全数据化,美术/策划可在 Inspector 中配置- BehaviorDesigner 调用
BossOrchestrator的 Action Task,不直接操作动画 - 阶段切换通过 SO 事件频道广播,不在 BossBase 内硬编码
2. 攻击模式数据层
AttackPatternSO — 单个攻击模式
[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 — 激活条件
[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 — 阶段配置
[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,负责模式选择与执行状态追踪。
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 攻击前通过多层视觉/音效预警给玩家反应时间。
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. 阶段转换规则
[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 中追加):
// 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.15s(HitBox开启 + 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.8s(Boss 喘息)
DamageType: Melee · Heavy · isParryable: ✗
推荐 weight: 1 · cooldown: 8s
条件: HPBelow(0.4)(仅在第二阶段以下使用)
6.5 多段连击(MultiHitCombo)
Telegraph: BodyFlash(白色,0.3s)
Windup: 0.1s
Active: 1.2s(3次HitBox依次开启,间隔0.3s,最后一击可弹反)
Recovery: 0.6s
DamageType: Melee · Light(1), Light(1), Medium(2)
isParryable: 第3击 ✓
推荐 weight: 5 · cooldown: 2s
7. Boss 原型模板
7.1 敏捷近战 Boss(AgileKnight)
设计核心:高移动速度、多次冲刺、强调弹反互动。
阶段 1(HP 100%~50%):
模式集: MeleeLunge(w4) · MultiHitCombo(w5) · ProjectileVolley(w2)
IdleGap: 0.8~1.5s · MaxCombo: 3
阶段 2(HP 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 远程投射 Boss(SorcererBoss)
设计核心:与玩家保持距离、多种弹道类型、Arena 控制。
阶段 1(HP 100%~60%):
模式集: ProjectileVolley(w5) · AreaDenial(w3)
条件: OutOfRange(5) 时强制使用 TeleportBehindPlayer 模式
IdleGap: 1.0~2.0s
阶段 2(HP 60%~0%):
新增模式: HomingProjectileSpray(向玩家发射3颗追踪弹)
IdleGap: 0.6~1.5s
过渡: 传送至场地中央 + FullBodyGlow 2s + 特殊动画
7.3 巨型多阶段 Boss(ColossalBoss)
设计核心:3个阶段、每阶段改变整体行为模式、标志性大招。
阶段 1(HP 100%~70%):
模式集: GroundSlam · MeleeLunge
弱点部位: HurtBox 仅在头部
阶段 2(HP 70%~35%):
新增模式: WallJump + AreaDenial组合(Boss跳墙后俯冲)
弱点部位: 头部 + 双手(3个 HurtBox)
阶段 3(HP 35%~0%):
HorizontalSweep + ProjectileVolley 组合使用
IdleGap 减至 0.3s
背景音乐切换至最终阶段曲
弱点部位: 全身开放
8. BehaviorDesigner 集成
自定义 Action Tasks
// 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