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

24 KiB
Raw Permalink Blame History

19 · Boss 攻击模式库Boss Pattern Library

命名空间 BaseGames.Enemies.Boss.Patterns
所属文档集 ← 返回索引 · 总览
依赖 BaseGames.Enemies · BaseGames.Combat · BaseGames.Feedback · BaseGames.Core.Events · BehaviorDesigner · Animancer


目录

  1. 系统总览
  2. 攻击模式数据层
  3. BossOrchestrator — 运行时编排器
  4. TelegraphSystem — 预警系统
  5. 阶段转换规则
  6. 内置攻击模式类型
  7. Boss 原型模板
  8. BehaviorDesigner 集成
  9. 事件频道
  10. 编辑器工具

1. 系统总览

Boss 攻击模式系统将 Boss 战的决策执行分离:

Boss 模式系统职责:
  ├─ AttackPatternSO      → 单个攻击的完整数据(前摇/活跃/后摇/伤害/移动/预警)
  ├─ BossPhaseConfigSO    → 一个阶段的模式集合(权重、冷却、组合规则)
  ├─ BossOrchestrator     → 运行时编排:选模式 → 执行 → 监听结果
  ├─ TelegraphSystem      → 攻击前的视觉/音效预警Surface Marker、闪光、UI 箭头)
  └─ PhaseTransitionRule  → HP 阈值 → 触发阶段切换

设计原则

  • AttackPatternSO 完全数据化,美术/策划可在 Inspector 中配置
  • BehaviorDesigner 调用 BossOrchestratorAction 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.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

// 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() GameManagerProgressionSystemCutsceneManager

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