using NUnit.Framework; using BaseGames.Enemies; namespace BaseGames.Tests.EditMode.Enemies { /// /// StallDetector:窗口内净位移不足即判停滞。 /// 该逻辑原本在 3 处各写一遍(巡逻 Pace / 导航层 / 冲锋),此处集中钉住行为。 /// public class StallDetectorTests { const float Window = 0.5f, MinProgress = 0.05f; [Test] public void BeforeWindowElapses_NeverStalled() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); Assert.IsFalse(d.Tick(0f, 0.1f)); // 完全没动,但窗口未到 Assert.IsFalse(d.Tick(0f, 0.1f)); } [Test] public void NoProgressOverWindow_Stalled() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); Assert.IsFalse(d.Tick(0f, 0.4f)); Assert.IsTrue (d.Tick(0f, 0.2f)); // 累计 0.6s ≥ 窗口,净位移 0 } [Test] public void EnoughProgressOverWindow_NotStalled() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); Assert.IsFalse(d.Tick(1f, 0.6f)); // 位移 1m 远超阈值 } [Test] public void ProgressJustBelowThreshold_Stalled() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); Assert.IsTrue(d.Tick(0.04f, 0.6f)); // 0.04 < 0.05 } [Test] public void ProgressCountsBothDirections() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); Assert.IsFalse(d.Tick(-1f, 0.6f)); // 向左移动同样算推进 } [Test] public void AfterStalled_WindowRestartsFromCurrentPosition() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); Assert.IsTrue (d.Tick(0f, 0.6f)); // 第一次判停滞 Assert.IsFalse(d.Tick(0f, 0.1f)); // 窗口已重开,未到期 Assert.IsTrue (d.Tick(0f, 0.6f)); // 再次到期且仍无推进 } [Test] public void Reset_ClearsAccumulatedTime() { var d = new StallDetector(Window, MinProgress); d.Reset(0f); d.Tick(0f, 0.4f); d.Reset(0f); // 重开窗口 Assert.IsFalse(d.Tick(0f, 0.2f)); // 只累计了 0.2s } [Test] public void WithoutReset_FirstTickInitializes() { var d = new StallDetector(Window, MinProgress); Assert.IsFalse(d.Tick(5f, 1f)); // 未 Reset 时首帧只做初始化,不误判 } } }