From 0253fd15ca95a58fec4b998690a1f4ce4f05e041 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Fri, 3 Jul 2026 14:09:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ai):=20BrainGraph=20Task4=20=E5=AE=A1?= =?UTF-8?q?=E6=9F=A5=E4=BF=AE=E5=A4=8D=E2=80=94=E2=80=94=E5=88=A0=E6=AD=BB?= =?UTF-8?q?=E5=AD=97=E6=AE=B5/Global=E7=A9=BA=E7=9B=AE=E6=A0=87=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C/AiState=E5=8F=AA=E8=AF=BB=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/_Game/Scripts/AI/AiState.cs | 6 +++++- Assets/_Game/Scripts/AI/BrainBuilder.cs | 15 +++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) 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; }