using System.Collections.Generic; using NUnit.Framework; using BaseGames.AI; using BaseGames.Enemies; namespace BaseGames.Tests.EditMode.AI { /// /// 回归测试:PerceptionStateMachine 的待机/巡逻/警觉声明 locomotion 意图, /// 追击走能力(不直接驱动 locomotion)。转换规则见 spec《敌人感知↔状态》。 /// public class PerceptionStateMachineTests { static AiGraph Graph() { var b = new BrainBuilder(); PerceptionStateMachine.Add(b, new PerceptionStateMachine.Config { Idle = "Idle", Patrol = "Patrol", Alert = "Alert", Chase = "Chase", Death = "Death", Entry = "Idle", Rest = "Patrol", IdleMode = LocomotionMode.Idle, PatrolMode = LocomotionMode.Patrol, AlertMode = LocomotionMode.Face, ChaseAbilityId = "chase", }); return b.Build(); } [Test] public void EntryIdleState_SetsIdleLocomotionMode() { var ctx = new FakeAiContext(); var rt = new AiRuntime(Graph(), ctx); Assert.AreEqual("Idle", rt.CurrentStateName); Assert.AreEqual(LocomotionMode.Idle, ctx.L.CurrentMode); // 进入待机即声明 Idle 意图 } [Test] public void InChaseZone_TransitionsToChase_AndTriggersChaseAbility() { var ctx = new FakeAiContext(); var rt = new AiRuntime(Graph(), ctx); ctx.S.Chase = true; // 进入追逐区 rt.Tick(0.1f); Assert.AreEqual("Chase", rt.CurrentStateName); CollectionAssert.Contains(ctx.C.Used, "chase"); // 追击由能力触发 } [Test] public void ChaseState_DoesNotDeclareLocomotionIntent() { // 追击移动归能力;AI 在 Chase 态不应再声明 SetMode/Approach/Face。 var ctx = new FakeAiContext(); var rt = new AiRuntime(Graph(), ctx); ctx.S.Chase = true; rt.Tick(0.1f); // Idle → Chase(退出 Idle 会调用一次 Stop) int lastStop = ctx.L.Calls.FindLastIndex(s => s == "Stop"); var afterEnteringChase = ctx.L.Calls.GetRange(lastStop + 1, ctx.L.Calls.Count - lastStop - 1); CollectionAssert.IsEmpty(afterEnteringChase); } } }