From 95011526b0c89d34ae6d8a6f5061e81a233f7ecd Mon Sep 17 00:00:00 2001 From: AkiKurisu <111233991+AkiKurisu@users.noreply.github.com> Date: Mon, 4 Sep 2023 16:32:34 +0800 Subject: [PATCH] Add Node Constraint --- Editor/Core/GOAPPlannerProEditor.cs | 12 ++- Editor/Node/GOAPNodeStack.cs | 24 ++++-- Editor/Window/GOAPEditorWindow.cs | 28 +++--- Editor/Window/GOAPView.cs | 118 +++++++++++++------------- Example/Scripts/Agent/AgentFactory.cs | 29 ++++--- 5 files changed, 114 insertions(+), 97 deletions(-) diff --git a/Editor/Core/GOAPPlannerProEditor.cs b/Editor/Core/GOAPPlannerProEditor.cs index 024d3f3..09dfa11 100644 --- a/Editor/Core/GOAPPlannerProEditor.cs +++ b/Editor/Core/GOAPPlannerProEditor.cs @@ -26,15 +26,19 @@ public override VisualElement CreateInspectorGUI() UIUtility.GetLabel("Normal Setting", 14, color: UIUtility.AkiBlue, anchor: TextAnchor.MiddleLeft).AddTo(myInspector); myInspector.Q("PropertyField:logType").MoveToEnd(myInspector); myInspector.Q("PropertyField:tickType").MoveToEnd(myInspector); - var isActive = new Toggle("Is Active"); - isActive.tooltip = SkilSearchTooltip; + var isActive = new Toggle("Is Active") + { + tooltip = SkilSearchTooltip + }; isActive.BindProperty(serializedObject.FindProperty("isActive")); isActive.AddTo(myInspector); myInspector.AddSpace(); UIUtility.GetLabel("Pro Setting", 14, color: UIUtility.AkiBlue, anchor: TextAnchor.MiddleLeft).AddTo(myInspector); var skipSearchProperty = serializedObject.FindProperty("skipSearchWhenActionRunning"); - var skipSearchToggle = new Toggle("Skip Search When Action Running"); - skipSearchToggle.tooltip = SkilSearchTooltip; + var skipSearchToggle = new Toggle("Skip Search When Action Running") + { + tooltip = SkilSearchTooltip + }; skipSearchToggle.BindProperty(skipSearchProperty); skipSearchToggle.AddTo(myInspector); //SnapShot diff --git a/Editor/Node/GOAPNodeStack.cs b/Editor/Node/GOAPNodeStack.cs index a2490c4..9b51826 100644 --- a/Editor/Node/GOAPNodeStack.cs +++ b/Editor/Node/GOAPNodeStack.cs @@ -6,11 +6,25 @@ public class GOAPNodeStack : StackNode { public GOAPNodeStack() { - capabilities&=~Capabilities.Copiable; - capabilities &=~Capabilities.Deletable;//不可删除 - capabilities &=~Capabilities.Movable;//不可删除 - headerContainer.style.flexDirection=FlexDirection.Row; - headerContainer.style.justifyContent=Justify.Center; + capabilities &= ~Capabilities.Copiable; + capabilities &= ~Capabilities.Deletable; + capabilities &= ~Capabilities.Movable; + headerContainer.style.flexDirection = FlexDirection.Row; + headerContainer.style.justifyContent = Justify.Center; + } + } + public class GOAPActionStack : GOAPNodeStack + { + protected override bool AcceptsElement(GraphElement element, ref int proposedIndex, int maxIndex) + { + return element is GOAPActionNode; + } + } + public class GOAPGoalStack : GOAPNodeStack + { + protected override bool AcceptsElement(GraphElement element, ref int proposedIndex, int maxIndex) + { + return element is GOAPGoalNode; } } } diff --git a/Editor/Window/GOAPEditorWindow.cs b/Editor/Window/GOAPEditorWindow.cs index efd9457..a17943b 100644 --- a/Editor/Window/GOAPEditorWindow.cs +++ b/Editor/Window/GOAPEditorWindow.cs @@ -7,8 +7,8 @@ namespace Kurisu.GOAP.Editor { public class GOAPEditorWindow : EditorWindow { - private static readonly Dictionary cache = new Dictionary(); - private UnityEngine.Object key { get; set; } + private static readonly Dictionary cache = new Dictionary(); + private UnityEngine.Object Key { get; set; } private GOAPView graphView; public static void ShowEditorWindow(IGOAPSet set) { @@ -18,21 +18,21 @@ public static void ShowEditorWindow(IGOAPSet set) cache[key].Focus(); return; } - var window = ScriptableObject.CreateInstance(); + var window = CreateInstance(); window.titleContent = new GUIContent($"GOAP Editor ({set._Object.name})"); window.Show(); window.Focus(); - window.key = set._Object; + window.Key = set._Object; cache[key] = window; window.StructGraphView(set); } private void StructGraphView(IGOAPSet set) { rootVisualElement.Clear(); - graphView=new GOAPView(this,set); + graphView = new GOAPView(this, set); graphView.Restore(); rootVisualElement.Add(CreateToolBar(graphView)); - rootVisualElement.Add(graphView); + rootVisualElement.Add(graphView); } private VisualElement CreateToolBar(GOAPView graphView) { @@ -41,15 +41,15 @@ private VisualElement CreateToolBar(GOAPView graphView) { GUILayout.BeginHorizontal(EditorStyles.toolbar); - GUI.enabled=!Application.isPlaying; + GUI.enabled = !Application.isPlaying; if (GUILayout.Button($"Save", EditorStyles.toolbarButton)) { var guiContent = new GUIContent(); graphView.Save(); guiContent.text = $"Update Succeed !"; - this.ShowNotification(guiContent); + ShowNotification(guiContent); } - GUI.enabled=true; + GUI.enabled = true; GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } @@ -86,17 +86,17 @@ private void OnDisable() } private void Reload() { - if (key != null) + if (Key != null) { - if(key is GameObject)StructGraphView((key as GameObject).GetComponent()); - else StructGraphView((key as IGOAPSet)); + if (Key is GameObject) StructGraphView((Key as GameObject).GetComponent()); + else StructGraphView(Key as IGOAPSet); Repaint(); } } private void OnDestroy() { - int code=key.GetHashCode(); - if (key != null && cache.ContainsKey(code)) + int code = Key.GetHashCode(); + if (Key != null && cache.ContainsKey(code)) { cache.Remove(code); } diff --git a/Editor/Window/GOAPView.cs b/Editor/Window/GOAPView.cs index 5fb97b4..cc2b481 100644 --- a/Editor/Window/GOAPView.cs +++ b/Editor/Window/GOAPView.cs @@ -8,20 +8,20 @@ namespace Kurisu.GOAP.Editor { public class GOAPView : GraphView { - private const string GraphStyleSheetPath="AkiGOAP/Graph"; - private const string GoalIconPath="Icons/goal_icon"; - private const string ActionIconPath="Icons/action_icon"; + private const string GraphStyleSheetPath = "AkiGOAP/Graph"; + private const string GoalIconPath = "Icons/goal_icon"; + private const string ActionIconPath = "Icons/action_icon"; private readonly EditorWindow editorWindow; - internal System.Action onSelectAction; - private IGOAPSet set; - public IGOAPSet Set=>set; + internal System.Action onSelectAction; + private readonly IGOAPSet set; + public IGOAPSet Set => set; private readonly NodeResolver nodeResolver = new NodeResolver(); private GOAPNodeStack goalStack; private GOAPNodeStack actionStack; - public GOAPView(EditorWindow editor,IGOAPSet set) + public GOAPView(EditorWindow editor, IGOAPSet set) { - this.set=set; - editorWindow=editor; + this.set = set; + editorWindow = editor; style.flexGrow = 1; style.flexShrink = 1; styleSheets.Add(Resources.Load(GraphStyleSheetPath)); @@ -39,19 +39,19 @@ public GOAPView(EditorWindow editor,IGOAPSet set) this.AddManipulator(new RectangleSelector()); this.AddManipulator(new FreehandSelector()); this.AddManipulator(contentDragger); - if(set is GOAPActionSet) + if (set is GOAPActionSet) { - var searchWindow=ScriptableObject.CreateInstance(); - searchWindow.Init(editorWindow,this); + var searchWindow = ScriptableObject.CreateInstance(); + searchWindow.Init(editorWindow, this); nodeCreationRequest += context => { SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchWindow); }; } - else if(set is GOAPGoalSet) + else if (set is GOAPGoalSet) { - var searchWindow=ScriptableObject.CreateInstance(); - searchWindow.Init(editorWindow,this); + var searchWindow = ScriptableObject.CreateInstance(); + searchWindow.Init(editorWindow, this); nodeCreationRequest += context => { SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchWindow); @@ -59,14 +59,14 @@ public GOAPView(EditorWindow editor,IGOAPSet set) } else { - var searchWindow=ScriptableObject.CreateInstance(); - searchWindow.Init(editorWindow,this); + var searchWindow = ScriptableObject.CreateInstance(); + searchWindow.Init(editorWindow, this); nodeCreationRequest += context => { SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchWindow); }; } - + } public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) { @@ -85,82 +85,80 @@ public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) } internal void Restore() { - goalStack=new GOAPNodeStack(); - goalStack.SetPosition (new Rect(100,300,100,100)); - goalStack.headerContainer.Add(new Image(){image=Resources.Load(GoalIconPath)}); + goalStack = new GOAPGoalStack(); + goalStack.SetPosition(new Rect(100, 300, 100, 100)); + goalStack.headerContainer.Add(new Image() { image = Resources.Load(GoalIconPath) }); goalStack.headerContainer.Add(new Label(" GOAP Goal Stack")); - actionStack=new GOAPNodeStack(); - actionStack.SetPosition (new Rect(600,300,100,100)); - actionStack.headerContainer.Add(new Image(){image=Resources.Load(ActionIconPath)}); + actionStack = new GOAPActionStack(); + actionStack.SetPosition(new Rect(600, 300, 100, 100)); + actionStack.headerContainer.Add(new Image() { image = Resources.Load(ActionIconPath) }); actionStack.headerContainer.Add(new Label(" GOAP Action Stack")); AddElement(goalStack); AddElement(actionStack); - if(set is GOAPActionSet) + if (set is GOAPActionSet) { goalStack.SetEnabled(false); } - if(set is GOAPGoalSet) + if (set is GOAPGoalSet) { actionStack.SetEnabled(false); } - foreach(var behavior in set.Behaviors) + foreach (var behavior in set.Behaviors) { - if(behavior==null)continue; - var node = nodeResolver.CreateNodeInstance(behavior.GetType(),this); + if (behavior == null) continue; + var node = nodeResolver.CreateNodeInstance(behavior.GetType(), this); node.Restore(behavior); - if(node is GOAPActionNode)actionStack.AddElement(node); + if (node is GOAPActionNode) actionStack.AddElement(node); else goalStack.AddElement(node); - node.onSelectAction=onSelectAction; + node.onSelectAction = onSelectAction; } - if(set is IPlanner) + if (set is IPlanner) { - IPlanner planner=set as IPlanner; - planner.OnUpdatePlanEvent+=UpdateView; + IPlanner planner = set as IPlanner; + planner.OnUpdatePlanEvent += UpdateView; } } private void UpdateView(IPlanner planner) { - var actions=actionStack.Query().ToList(); - actions.ForEach(x=>x.CleanUp()); - var goals=goalStack.Query().ToList(); - goals.ForEach(x=>x.CleanUp()); - var activePlans=planner.ActivatePlan; - var activeGoal=planner.ActivateGoal; - foreach(var action in activePlans) + var actions = actionStack.Query().ToList(); + actions.ForEach(x => x.CleanUp()); + var goals = goalStack.Query().ToList(); + goals.ForEach(x => x.CleanUp()); + var activePlans = planner.ActivatePlan; + var activeGoal = planner.ActivateGoal; + foreach (var action in activePlans) { - var goapAction=action as GOAPAction; - if(goapAction==null)continue; - var t_Action=actions.First(x=>x.GUID==goapAction.GUID); + if (action is not GOAPAction goapAction) continue; + var t_Action = actions.First(x => x.GUID == goapAction.GUID); (t_Action as GOAPActionNode).SetUp(goapAction.GetCost()); } - var goapGoal=activeGoal as GOAPGoal; - if(goapGoal==null)return; - var t_Goal=goals.First(x=>x.GUID==goapGoal.GUID); - (t_Goal as GOAPGoalNode).SetUp(goapGoal.GetPriority(),goapGoal.PreconditionsSatisfied(planner.WorldState),true); - foreach(var goal in goals) + if (activeGoal is not GOAPGoal goapGoal) return; + var t_Goal = goals.First(x => x.GUID == goapGoal.GUID); + (t_Goal as GOAPGoalNode).SetUp(goapGoal.GetPriority(), goapGoal.PreconditionsSatisfied(planner.WorldState), true); + foreach (var goal in goals) { - if(goal==t_Goal)continue; - var goalBehavior=planner.Behaviors.First(x=>x.GUID==goal.GUID) as GOAPGoal; - (goal as GOAPGoalNode).SetUp(goalBehavior.GetPriority(),goalBehavior.PreconditionsSatisfied(planner.WorldState),false); + if (goal == t_Goal) continue; + var goalBehavior = planner.Behaviors.First(x => x.GUID == goal.GUID) as GOAPGoal; + (goal as GOAPGoalNode).SetUp(goalBehavior.GetPriority(), goalBehavior.PreconditionsSatisfied(planner.WorldState), false); } } internal void Save() { - if(Application.isPlaying)return; + if (Application.isPlaying) return; set.Behaviors.Clear(); IEnumerable list; - if(set is GOAPActionSet) + if (set is GOAPActionSet) { - list=actionStack.Query().ToList(); + list = actionStack.Query().ToList(); } - else if(set is GOAPGoalSet) + else if (set is GOAPGoalSet) { - list=goalStack.Query().ToList(); + list = goalStack.Query().ToList(); } - else list=goalStack.Query().ToList().Concat(actionStack.Query().ToList()); - foreach(var node in list) + else list = goalStack.Query().ToList().Concat(actionStack.Query().ToList()); + foreach (var node in list) { - node.Commit(); + node.Commit(); set.Behaviors.Add(node.NodeBehavior); } EditorUtility.SetDirty(set._Object); diff --git a/Example/Scripts/Agent/AgentFactory.cs b/Example/Scripts/Agent/AgentFactory.cs index d95bce3..508d65e 100644 --- a/Example/Scripts/Agent/AgentFactory.cs +++ b/Example/Scripts/Agent/AgentFactory.cs @@ -6,7 +6,7 @@ public class AgentFactory : MonoBehaviour [SerializeField] private GameObject agentPrefab; [SerializeField] - private int maxAmount=1000; + private int maxAmount = 1000; [SerializeField] private Transform player; [SerializeField] @@ -15,33 +15,34 @@ public class AgentFactory : MonoBehaviour private Transform tent; [SerializeField] private GOAPSet dataSet; - [SerializeField] private ExampleAgent[] agents; - private void Awake() { - agents=new ExampleAgent[maxAmount]; - for(int i=0;i