NodeCanvas Forums › General Discussion › SuperActionList Kind of Like SuperActionState
Hi,
I create a class kind of like SuperActionState to have a onExitList in ActionList for behavior tree.
Here is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
#if UNITY_EDITOR using UnityEditor; #endif using System.Collections.Generic; using ParadoxNotion.Design; using UnityEngine; namespace NodeCanvas.Framework { // Like ActionList, but it will also run the _onExitList when we are exiting this SuperActionList public class SuperActionList : ActionList { [SerializeField] private ActionList _onExitList; public override void OnValidate(ITaskSystem ownerSystem) { base.OnValidate(ownerSystem); if (_onExitList == null) { _onExitList = (ActionList)Task.Create(typeof(ActionList), ownerSystem); _onExitList.executionMode = ActionList.ActionsExecutionMode.ActionsRunInSequence; } else { _onExitList.SetOwnerSystem(ownerSystem); foreach (var inAction in _onExitList.actions) { inAction.SetOwnerSystem(ownerSystem); } } } ///SuperActionList overrides to duplicate listed actions correctly public override Task Duplicate(ITaskSystem newOwnerSystem) { var newList = (SuperActionList)base.Duplicate(newOwnerSystem); newList._onExitList = (ActionList)_onExitList.Duplicate(newOwnerSystem); return newList; } protected override void OnStop() { base.OnStop(); _onExitList.ExecuteAction(agent, blackboard); } protected override void OnPause() { base.OnPause(); for (var i = 0; i < _onExitList.actions.Count; i++) { _onExitList.actions<em class="d4pbbc-italic"></em>.PauseAction(); } } void AddAction(List<ActionTask> list, ActionTask action) { if (action is ActionList) { Debug.LogWarning("Adding an ActionList within another ActionList is not allowed for clarity"); return; } #if UNITY_EDITOR if (!Application.isPlaying) { Undo.RecordObject(ownerSystem.contextObject, "List Add Task"); currentViewAction = action; } #endif list.Add(action); action.SetOwnerSystem(this.ownerSystem); } //////////////////////////////////////// ///////////GUI AND EDITOR STUFF///////// //////////////////////////////////////// [SerializeField] private bool foldUpdate; [SerializeField] private bool foldExit; #if UNITY_EDITOR protected override void OnTaskInspectorGUI() { EditorUtils.CoolLabel("Actions"); foldUpdate = UnityEditor.EditorGUILayout.Foldout(foldUpdate, "OnUpdate Actions (Run like regular Action List)"); if (foldUpdate) { ShowListGUI(); ShowNestedActionsGUI(); } EditorUtils.Separator(); foldExit = UnityEditor.EditorGUILayout.Foldout(foldExit, "OnExit Actions (Run these when exit)"); if (foldExit) { _onExitList.ShowListGUI(); _onExitList.ShowNestedActionsGUI(); } } #endif } } |
The problem is other action will get called before the _onExitList execute. In the picture below. When I click the TestBool1, the first branch will execute first and set TestFloat1 to 1. Then the _onExitList execute to set TestFloat1 to 2. This is not the behavior I want. It should act more like state machine, which the _onExitList get called first, then set TestFloat1 to 1.
Hey,
Thanks for sharing.
Have you tried called base.Stop()
after _onExitList.ExecuteAction(agent, blackboard);
?
Join us on Discord: https://discord.gg/97q2Rjh
I tried it and it didn’t work.
I think mainly is because how the tree/nodes get traverse. Currently, I am using 2.5.6c and here is the Selector.OnExecute.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
protected override Status OnExecute(Component agent, IBlackboard blackboard){ for ( var i= dynamic? 0 : lastRunningNodeIndex; i < outConnections.Count; i++){ status = outConnections<em class="d4pbbc-italic"></em>.Execute(agent, blackboard); switch(status) { case Status.Running: if (dynamic && i < lastRunningNodeIndex) outConnections[lastRunningNodeIndex].Reset(); lastRunningNodeIndex = i; return Status.Running; case Status.Success: if (dynamic && i < lastRunningNodeIndex) outConnections[lastRunningNodeIndex].Reset(); return Status.Success; } } return Status.Failure; } |
In my example, the Selector is dynamic, that’s why Reset is called after Execute. So I need a way to know if the condition is met, it will run Reset first. Same thing in Sequencer. This class is pretty helpful, I always like the idea of clean itself up. So you don’t need to put clean up code everywhere. So I would like to have some help to make this work. Cheers.
Anything about this update?
Or maybe other way that I can interrupt the tree and run a list of nodes first, then resume back to the dynamic nodes?
Please help.