refactor(ai): AiSignal 8→1,删除零发送方零消费方的死枚举
This commit is contained in:
@@ -107,10 +107,10 @@ namespace BaseGames.Tests.EditMode.AI
|
|||||||
b.Entry("A");
|
b.Entry("A");
|
||||||
b.State("A")
|
b.State("A")
|
||||||
.To("ByCond").When(c => true, "cond") // 条件恒真
|
.To("ByCond").When(c => true, "cond") // 条件恒真
|
||||||
.To("ByEvent").OnEvent(AiSignal.Parried); // 事件优先(Tick 第1步)
|
.To("ByEvent").OnEvent(AiSignal.Died); // 事件优先(Tick 第1步)
|
||||||
b.State("ByCond"); b.State("ByEvent");
|
b.State("ByCond"); b.State("ByEvent");
|
||||||
var rt = new AiRuntime(b.Build(), new FakeAiContext());
|
var rt = new AiRuntime(b.Build(), new FakeAiContext());
|
||||||
rt.Send(AiSignal.Parried);
|
rt.Send(AiSignal.Died);
|
||||||
rt.Tick(0.1f);
|
rt.Tick(0.1f);
|
||||||
Assert.AreEqual("ByEvent", rt.CurrentStateName);
|
Assert.AreEqual("ByEvent", rt.CurrentStateName);
|
||||||
}
|
}
|
||||||
@@ -125,27 +125,30 @@ namespace BaseGames.Tests.EditMode.AI
|
|||||||
var ctx = new FakeAiContext();
|
var ctx = new FakeAiContext();
|
||||||
ctx.S.Sees = true;
|
ctx.S.Sees = true;
|
||||||
var rt = new AiRuntime(b.Build(), ctx);
|
var rt = new AiRuntime(b.Build(), ctx);
|
||||||
rt.Send(AiSignal.Parried); // A 无 Parried 转换 → 被消费掉,不阻塞条件评估
|
rt.Send(AiSignal.Died); // A 无 Died 转换 → 被消费掉,不阻塞条件评估
|
||||||
rt.Tick(0.1f);
|
rt.Tick(0.1f);
|
||||||
Assert.AreEqual("B", rt.CurrentStateName);
|
Assert.AreEqual("B", rt.CurrentStateName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void MultipleQueuedSignals_FirstMatchWins_RemainingConsumed()
|
public void QueuedDuplicateSignals_TransitionOnce_RemainderConsumed()
|
||||||
{
|
{
|
||||||
|
// 注:原测试用两个不同信号验证"第一个匹配的先转"。AiSignal 现只有 Died 一个值,
|
||||||
|
// 该形态暂不可表达;等将来出现第二个真实信号(如战斗激活)时恢复此覆盖。
|
||||||
|
// 此处覆盖仍然成立的部分:残留信号被消费掉,不会重复触发转换。
|
||||||
var b = new BrainBuilder();
|
var b = new BrainBuilder();
|
||||||
b.Entry("A");
|
b.Entry("A");
|
||||||
b.State("A")
|
b.State("A").To("B").OnEvent(AiSignal.Died);
|
||||||
.To("B").OnEvent(AiSignal.Parried)
|
b.State("B").OnEnter(c => c.Blackboard.Set("enters", c.Blackboard.Get<int>("enters") + 1));
|
||||||
.To("C").OnEvent(AiSignal.Staggered);
|
var ctx = new FakeAiContext();
|
||||||
b.State("B"); b.State("C");
|
var rt = new AiRuntime(b.Build(), ctx);
|
||||||
var rt = new AiRuntime(b.Build(), new FakeAiContext());
|
rt.Send(AiSignal.Died);
|
||||||
rt.Send(AiSignal.Parried);
|
rt.Send(AiSignal.Died);
|
||||||
rt.Send(AiSignal.Staggered);
|
|
||||||
rt.Tick(0.1f);
|
rt.Tick(0.1f);
|
||||||
Assert.AreEqual("B", rt.CurrentStateName); // 第一个匹配的 Parried 先转 B
|
Assert.AreEqual("B", rt.CurrentStateName);
|
||||||
rt.Tick(0.1f);
|
rt.Tick(0.1f);
|
||||||
Assert.AreEqual("B", rt.CurrentStateName); // 残留 Staggered 在 B 无匹配 → 被消费,仍 B
|
Assert.AreEqual("B", rt.CurrentStateName);
|
||||||
|
Assert.AreEqual(1, ctx.BB.Get<int>("enters")); // 残留信号被消费,未重入 B
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 自转换 / OnTick 时序 ──────────────────────────────────────────
|
// ── 自转换 / OnTick 时序 ──────────────────────────────────────────
|
||||||
|
|||||||
@@ -165,11 +165,11 @@ namespace BaseGames.Tests.EditMode.AI
|
|||||||
{
|
{
|
||||||
var b = new BrainBuilder();
|
var b = new BrainBuilder();
|
||||||
b.Entry("Idle");
|
b.Entry("Idle");
|
||||||
b.State("Idle").To("Flee").OnEvent(AiSignal.Parried);
|
b.State("Idle").To("Flee").OnEvent(AiSignal.Died);
|
||||||
b.State("Flee");
|
b.State("Flee");
|
||||||
var ctx = new FakeAiContext();
|
var ctx = new FakeAiContext();
|
||||||
var rt = new AiRuntime(b.Build(), ctx);
|
var rt = new AiRuntime(b.Build(), ctx);
|
||||||
rt.Send(AiSignal.Parried);
|
rt.Send(AiSignal.Died);
|
||||||
rt.Tick(0.1f);
|
rt.Tick(0.1f);
|
||||||
Assert.AreEqual("Flee", rt.CurrentStateName);
|
Assert.AreEqual("Flee", rt.CurrentStateName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
namespace BaseGames.AI
|
namespace BaseGames.AI
|
||||||
{
|
{
|
||||||
/// <summary>决策层的推送信号,用于事件驱动的状态转换(不靠轮询)。</summary>
|
/// <summary>
|
||||||
|
/// 决策层的推送信号,用于事件驱动的状态转换(不靠轮询)。
|
||||||
|
///
|
||||||
|
/// 只保留真实存在发送方与消费方的信号。受击 / 硬直 / 击飞 / 弹反**不在此列**——
|
||||||
|
/// 它们由敌人物理状态机(EnemyStateType)处理,决策层经 IActorVitals.IsControllable
|
||||||
|
/// 让位门自动挂起。在这里重复定义会诱导写出与物理层打架的第二套受击逻辑。
|
||||||
|
///
|
||||||
|
/// 新增信号的判据:已经有确定的发送方与消费方,否则不要预留。
|
||||||
|
/// </summary>
|
||||||
public enum AiSignal
|
public enum AiSignal
|
||||||
{
|
{
|
||||||
Damaged, // 受到伤害
|
Died,
|
||||||
Parried, // 被弹反
|
|
||||||
Staggered, // 进入硬直
|
|
||||||
KnockedUp, // 被击飞
|
|
||||||
Died, // 死亡
|
|
||||||
PlayerSpotted,// 首次侦测到玩家
|
|
||||||
AbilityEnded, // 当前能力协程结束/被打断
|
|
||||||
PhaseChanged // Boss 阶段变更
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user