Files
zeling_v2/Assets/_Game/Scripts/Enemies/AIBrain/Modules/BossFragments.cs
T
joywayerandClaude Opus 5 eaba54ea76 feat(ai): Boss 图共享片段 + 竞技场锚点 + AiSignal.Engaged
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>
2026-07-30 14:32:32 +08:00

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;
}
}