From 63e241af922af811235e179bce556fd972463cda Mon Sep 17 00:00:00 2001 From: Joywayer Date: Fri, 3 Jul 2026 16:26:28 +0800 Subject: [PATCH] =?UTF-8?q?fix(ai):=20AiRuntime=20=E8=87=AA=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E8=AE=BE=E4=B8=BAno-op(=E6=A0=B9=E6=B2=BB=E6=AD=BB?= =?UTF-8?q?=E4=BA=A1=E5=8F=8C=E5=8F=91Died=E5=86=8D=E5=85=A5)=20+=20EnemyB?= =?UTF-8?q?ase.OnSpawn=E5=A4=8D=E4=BD=8Dbrain.enabled=20+=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch 对 target==当前态直接 no-op(不重跑Exit/Enter),循环改为 if(Switch(t))return true; OnSpawn 复用时恢复被 QuotaManager 裁剪禁用的 brain。 Co-Authored-By: Claude Opus 4.8 (1M context) --- Assets/Tests/EditMode/AI/AiRuntimeTests.cs | 17 +++++++++++++++++ Assets/_Game/Scripts/AI/AiRuntime.cs | 9 +++++---- Assets/_Game/Scripts/Enemies/EnemyBase.cs | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Assets/Tests/EditMode/AI/AiRuntimeTests.cs b/Assets/Tests/EditMode/AI/AiRuntimeTests.cs index a650d32e..0a4a2aa1 100644 --- a/Assets/Tests/EditMode/AI/AiRuntimeTests.cs +++ b/Assets/Tests/EditMode/AI/AiRuntimeTests.cs @@ -174,6 +174,23 @@ namespace BaseGames.Tests.EditMode.AI Assert.AreEqual("Flee", rt.CurrentStateName); } + [Test] + public void EventSelfTransition_DoesNotReenter() + { + var b = new BrainBuilder(); + b.Entry("Dead"); + int enterCount = 0; + b.State("Dead").OnEnter(c => enterCount++); + b.Global().To("Dead").OnEvent(AiSignal.Died); + var ctx = new FakeAiContext(); + var rt = new AiRuntime(b.Build(), ctx); + // 构造即进入 Dead → enterCount==1 + rt.Send(AiSignal.Died); + rt.Tick(0.1f); // 已在 Dead,自转换应 no-op,不再 +1 + Assert.AreEqual(1, enterCount); + Assert.AreEqual("Dead", rt.CurrentStateName); + } + [Test] public void TwoRuntimes_ShareGraph_IndependentStateAndTimer() { diff --git a/Assets/_Game/Scripts/AI/AiRuntime.cs b/Assets/_Game/Scripts/AI/AiRuntime.cs index 51783243..d568b730 100644 --- a/Assets/_Game/Scripts/AI/AiRuntime.cs +++ b/Assets/_Game/Scripts/AI/AiRuntime.cs @@ -85,7 +85,7 @@ namespace BaseGames.AI { var t = globals[i]; if (!t.IsEvent && t.Condition(_ctx)) - return Switch(t); + { if (Switch(t)) return true; } } var locals = _current.Transitions; @@ -93,7 +93,7 @@ namespace BaseGames.AI { var t = locals[i]; if (!t.IsEvent && t.Condition(_ctx)) - return Switch(t); + { if (Switch(t)) return true; } } return false; @@ -106,7 +106,7 @@ namespace BaseGames.AI { var t = globals[i]; if (t.IsEvent && t.Event.Value == sig) - return Switch(t); + { if (Switch(t)) return true; } } var locals = _current.Transitions; @@ -114,13 +114,14 @@ namespace BaseGames.AI { var t = locals[i]; if (t.IsEvent && t.Event.Value == sig) - return Switch(t); + { if (Switch(t)) return true; } } return false; } bool Switch(Transition t) { + if (t.Target == _current.Name) return false; // 自转换:no-op,不重跑 Exit/Enter var from = _current.Name; _current.OnExit?.Invoke(_ctx); _current = _graph.GetState(t.Target); diff --git a/Assets/_Game/Scripts/Enemies/EnemyBase.cs b/Assets/_Game/Scripts/Enemies/EnemyBase.cs index f563e4ef..1b4fa08a 100644 --- a/Assets/_Game/Scripts/Enemies/EnemyBase.cs +++ b/Assets/_Game/Scripts/Enemies/EnemyBase.cs @@ -724,6 +724,7 @@ namespace BaseGames.Enemies _abilities.InterruptAll(InterruptReason.Dead); // 重置决策层(回到 Entry、清临时态) + if (_brain != null) _brain.enabled = true; // 复用时恢复决策组件(可能曾被 QuotaManager 裁剪禁用) _brain?.ResetBrain(); // 通知配置型出生行为组件(如 EnemyAbilityTrigger)执行出生触发逻辑