From 63b3701fc77896ad2d814a22488369c3a67963ac Mon Sep 17 00:00:00 2001 From: Joywayer Date: Fri, 10 Jul 2026 12:21:28 +0800 Subject: [PATCH] =?UTF-8?q?@=20test(ai):=20PerceptionStateMachine=20locomo?= =?UTF-8?q?tion=20=E6=84=8F=E5=9B=BE=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95(?= =?UTF-8?q?=E7=BB=BF)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 PerceptionStateMachineTests:待机态声明 Idle locomotion 意图、进追逐区 转 Chase 并触发追击能力、Chase 态不再直接声明 locomotion 意图。测试程序集 补 BaseGames.Enemies 引用。断言经真实状态机 + 测试 fake 验证通过。 Co-Authored-By: Claude Opus 4.8 (1M context) @ --- .../AI/PerceptionStateMachineTests.cs | 62 +++++++++++++++++++ .../AI/PerceptionStateMachineTests.cs.meta | 11 ++++ .../EditMode/BaseGames.Tests.EditMode.asmdef | 1 + 3 files changed, 74 insertions(+) create mode 100644 Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs create mode 100644 Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs.meta diff --git a/Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs b/Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs new file mode 100644 index 00000000..0b60e833 --- /dev/null +++ b/Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs @@ -0,0 +1,62 @@ +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); + } + } +} diff --git a/Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs.meta b/Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs.meta new file mode 100644 index 00000000..0ce20998 --- /dev/null +++ b/Assets/Tests/EditMode/AI/PerceptionStateMachineTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11d9c7954aefbd84e93387db27268546 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef b/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef index b60c3944..69b5e4ed 100644 --- a/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef +++ b/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef @@ -6,6 +6,7 @@ "BaseGames.Combat", "BaseGames.Core", "BaseGames.AI", + "BaseGames.Enemies", "BaseGames.Core.Events", "BaseGames.Core.Save", "BaseGames.EventChain",