diff --git a/Assets/_Game/Scripts/AI/AiState.cs b/Assets/_Game/Scripts/AI/AiState.cs
index 20019f7e..b95bf287 100644
--- a/Assets/_Game/Scripts/AI/AiState.cs
+++ b/Assets/_Game/Scripts/AI/AiState.cs
@@ -6,11 +6,15 @@ namespace BaseGames.AI
/// 一个状态:进入/每帧/退出钩子 + 出边转换列表(按优先级有序,首个命中即转)。
public sealed class AiState
{
+ readonly List _transitions = new List();
+
public string Name { get; }
public Action OnEnter { get; internal set; }
public Action OnTick { get; internal set; } // (ctx, dt)
public Action OnExit { get; internal set; }
- public List Transitions { get; } = new List();
+ public IReadOnlyList Transitions => _transitions;
+
+ internal void AddTransition(Transition t) => _transitions.Add(t);
public AiState(string name) => Name = name;
}
diff --git a/Assets/_Game/Scripts/AI/BrainBuilder.cs b/Assets/_Game/Scripts/AI/BrainBuilder.cs
index 0bc00d36..04269e24 100644
--- a/Assets/_Game/Scripts/AI/BrainBuilder.cs
+++ b/Assets/_Game/Scripts/AI/BrainBuilder.cs
@@ -61,17 +61,16 @@ namespace BaseGames.AI
public StateBuilder Tick(Action fn) { _state.OnTick = fn; return this; }
public StateBuilder OnExit(Action fn) { _state.OnExit = fn; return this; }
- public TransitionBuilder To(string target) => new TransitionBuilder(_owner, this, _state, target);
+ public TransitionBuilder To(string target) => new TransitionBuilder(this, _state, target);
}
public sealed class TransitionBuilder
{
- readonly BrainBuilder _owner;
readonly StateBuilder _stateBuilder;
readonly AiState _state;
readonly string _target;
- internal TransitionBuilder(BrainBuilder owner, StateBuilder sb, AiState state, string target)
- { _owner = owner; _stateBuilder = sb; _state = state; _target = target; }
+ internal TransitionBuilder(StateBuilder sb, AiState state, string target)
+ { _stateBuilder = sb; _state = state; _target = target; }
///
/// 条件转换。label 为可读标签(用于 Mermaid 边 / trace 触发原因),
@@ -79,14 +78,14 @@ namespace BaseGames.AI
///
public StateBuilder When(Func cond, string label = null)
{
- _state.Transitions.Add(Transition.OnCondition(_target, cond, label ?? "cond"));
+ _state.AddTransition(Transition.OnCondition(_target, cond, label ?? "cond"));
return _stateBuilder;
}
/// 事件转换。
public StateBuilder OnEvent(AiSignal evt)
{
- _state.Transitions.Add(Transition.OnEvent(_target, evt));
+ _state.AddTransition(Transition.OnEvent(_target, evt));
return _stateBuilder;
}
@@ -108,12 +107,16 @@ namespace BaseGames.AI
public GlobalBuilder OnEvent(AiSignal evt)
{
+ if (_pendingTarget == null)
+ throw new System.InvalidOperationException("Global(): 请先调用 To(target) 再 OnEvent/When。");
_owner.AddGlobal(Transition.OnEvent(_pendingTarget, evt));
return this;
}
public GlobalBuilder When(Func cond, string label = null)
{
+ if (_pendingTarget == null)
+ throw new System.InvalidOperationException("Global(): 请先调用 To(target) 再 OnEvent/When。");
_owner.AddGlobal(Transition.OnCondition(_pendingTarget, cond, label ?? "cond"));
return this;
}