BossFragments:阶段过渡 / 逼近选招 / 移动到锚点三个静态建态片段。 ApproachAttackEngagement 的建态逻辑提为 internal static Declare(态名参数化), 模块路径与 Boss 图路径共用同一份行为,Boss 可建多组(地面组/空中组)。 锚点坐标经 IBossControl.AnchorAt / DistanceToAnchor 暴露,不走黑板—— EnemyAiBrain._context 是私有的(BossBase 无从写入),且 ResetScratch 会清黑板 带来隐式时序约束。锚点本就是 Boss 专属知识,归 Boss facet 更直。 锚点漏配 / 下标越界显式抛,不回退到自身位置。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
65 lines
3.2 KiB
C#
65 lines
3.2 KiB
C#
using System;
|
|
using BaseGames.AI;
|
|
|
|
namespace BaseGames.Enemies
|
|
{
|
|
/// <summary>
|
|
/// Boss 图的共享建态片段。与 <see cref="AiStateFragments"/> 同级——是静态建态原语,
|
|
/// 不是可插拔模块:Boss 图手写,重复的形状抽成片段即可,不需要 SO 下拉与多态序列化。
|
|
/// </summary>
|
|
public static class BossFragments
|
|
{
|
|
/// <summary>
|
|
/// 阶段过渡态:进入时发起过渡(无敌 + 演出由 BossBase 负责),过渡结束后由调用方挂出边。
|
|
/// 只发起一次——放 OnEnter 而非 Tick,因为 BossBase.BeginPhaseTransition 对重入会告警。
|
|
/// </summary>
|
|
public static BrainBuilder.StateBuilder PhaseTransition(
|
|
BrainBuilder b, string state, int targetPhase, float invincibleDuration)
|
|
{
|
|
if (targetPhase < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(targetPhase),
|
|
$"BossFragments.PhaseTransition: 状态 '{state}' 的目标阶段不能为负。");
|
|
if (invincibleDuration <= 0f)
|
|
throw new ArgumentOutOfRangeException(nameof(invincibleDuration),
|
|
$"BossFragments.PhaseTransition: 状态 '{state}' 的无敌时长必须 > 0——" +
|
|
"为 0 意味着过渡演出期间可被打断,这不是阶段过渡的语义。");
|
|
|
|
return b.DeclareState(state)
|
|
.OnEnter(x =>
|
|
{
|
|
x.Locomotion.Stop();
|
|
x.Combat.InterruptAbilities();
|
|
x.Boss.BeginPhaseTransition(targetPhase, invincibleDuration);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 一组「逼近 ↔ 到射程选招攻击」。转发到 ApproachAttackEngagement 的共享实现,
|
|
/// 使模块路径与 Boss 图路径永远是同一份行为。
|
|
/// 返回逼近态的 builder,调用方可继续挂阶段过渡等出边。
|
|
/// </summary>
|
|
public static BrainBuilder.StateBuilder ApproachAttack(
|
|
BrainBuilder b, string approach, string attack, string rest)
|
|
=> ApproachAttackEngagement.Declare(b, approach, attack, rest);
|
|
|
|
/// <summary>
|
|
/// 移动到第 index 个竞技场锚点(<see cref="BossArenaAnchors"/>),到位后由调用方挂出边。
|
|
/// 坐标经 IBossControl 取得——声明层的 lambda 不得闭包捕获具体实例。
|
|
/// </summary>
|
|
public static BrainBuilder.StateBuilder MoveToAnchor(BrainBuilder b, string state, int index)
|
|
{
|
|
if (index < 0)
|
|
throw new ArgumentOutOfRangeException(nameof(index),
|
|
$"BossFragments.MoveToAnchor: 状态 '{state}' 的锚点下标不能为负。");
|
|
|
|
return b.DeclareState(state)
|
|
.OnEnter(x => x.Locomotion.MoveTo(x.Boss.AnchorAt(index)))
|
|
.OnExit (x => x.Locomotion.Stop());
|
|
}
|
|
|
|
/// <summary>共享条件:已到达第 index 个锚点(容差内)。</summary>
|
|
public static Func<IAiContext, bool> AtAnchor(int index, float tolerance = 0.2f)
|
|
=> x => x.Boss.DistanceToAnchor(index) <= tolerance;
|
|
}
|
|
}
|