using System; using BaseGames.AI; namespace BaseGames.Enemies { /// /// Boss 图的共享建态片段。与 同级——是静态建态原语, /// 不是可插拔模块:Boss 图手写,重复的形状抽成片段即可,不需要 SO 下拉与多态序列化。 /// public static class BossFragments { /// /// 阶段过渡态:进入时发起过渡(无敌 + 演出由 BossBase 负责),过渡结束后由调用方挂出边。 /// 只发起一次——放 OnEnter 而非 Tick,因为 BossBase.BeginPhaseTransition 对重入会告警。 /// 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); }); } /// /// 一组「逼近 ↔ 到射程选招攻击」。转发到 ApproachAttackEngagement 的共享实现, /// 使模块路径与 Boss 图路径永远是同一份行为。 /// 返回逼近态的 builder,调用方可继续挂阶段过渡等出边。 /// public static BrainBuilder.StateBuilder ApproachAttack( BrainBuilder b, string approach, string attack, string rest) => ApproachAttackEngagement.Declare(b, approach, attack, rest); /// /// 移动到第 index 个竞技场锚点(),到位后由调用方挂出边。 /// 坐标经 IBossControl 取得——声明层的 lambda 不得闭包捕获具体实例。 /// 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()); } /// 共享条件:已到达第 index 个锚点(容差内)。 public static Func AtAnchor(int index, float tolerance = 0.2f) => x => x.Boss.DistanceToAnchor(index) <= tolerance; } }