NodeCanvas Forums › Support › Re-evaluation of action node differs if it is in a subtree or not
I think I have an issue that is related to (or same as in https://nodecanvas.paradoxnotion.com/forums/topic/not-expected-subtree-reset/)
My issue is that I get different kind of behavior in my tree if my node is encapsulated in a subtree or not.
My action-node evaluation depends on two objects and both has a simple script (ReadyObject) that has a bool field isReady. One of the objects (TheAgent) is connected as agent and one (TheObject) as a BBParameter<ReadyObject>. (It doesn’t really matter if it is an agent or two BBParameters)
The logic for my action task in quasi code
1 2 3 |
if (theAgent.IsReady == false) return fail; else if (theObject.IsReady == true) return success; else return running; |
To show the issue I found, I have added a Binary Selector so I can switch between using a node and subtree – where the subtree only has a copy of the same node in it with agent and object bound to it.
My issue starts to occur then I have managed to get my node to evaluate to success so I get to the next step that is a “forever”-running task (in my example, just a wait-until-decorator that keeps evalutate to false)
When I get to the state that the “forever”-node is running, and I use my task in a simple action-node, re-evaluation of the task won’t happen when change TheAgent.isReady or TheObject.isReady to false. But when I use the action-node from within a subtree it will be re-evaluted each tick thus the state will change between succeed, failed and running, depending on the values of TheAgent.isReady and TheObject.isReady.
I am not sure what is is the designed or desired behavior, the single-node behavior or the wrapped-in-subtree node behavior, but having different behaviors seems to be wrong.
In my current use case I would like it to be that the ActionNode will keep re-evaluating as it is doing when wrapped in a subtree, but I guess that might cause other problems in other use-cases or might have some preformance impact.
What do you say is the correct behavior?
The attached screenshots shows the different behaviors after we have been in the “forever”-running state with TheAgent.isReady = true and TheObject.isReady = true
and setting the TheAgent.isReady = false and setting TheObject.isReady = false
where left hand part is when evaluating as a plain node and righthand side evaluating the node in a subtree.
I attach the sandbox
with my script and tree if you want to try out.
When in running-mode just change the isReady-field on the ReadyObject-component script attached TheAgent and TheObject in the inspector to fiddle around with the behavior. To change between the node-mode and subtree mode you will need to change a variable in the graph blackboard
Hello there and thanks for the info.
Please let me clarify. The confusion comes specifically because of the “Dynamic” option and how that works differently for Action Task children versus Condition Task children. The behaviour of the Action Node you have here is the correct one. Action nodes do not re-evaluate per-frame even if their parent is set to be Dynamic. That is because Action nodes can also return Running and if they were to be re-evaluated, then they would not let the other nodes run at all. To demonstrate this please open up ActionNode.cs and comment out lines #38 and #40 as shown bellow.
1 2 3 4 5 |
// if ( status == Status.Resting || status == Status.Running ) { return action.Execute(agent, blackboard); // } |
Then create a simple behaviour tree like this:
When you enter play mode you will see that as soon as the left wait action is finished and execution moves to the second one, the first wait action is instantly “re-enabled” and interrupts the second one. Without the code change stated above (thus the original code), both wait action tasks execute normally one after the other, which is of course the correct behaviour. This is because Actions are handled differently than other nodes so that they can work correctly in the context of Dynamic parents (as shown in the original code)
SubTrees on the other hand do not make that distinction since they can contain any type of node and as such this special handling is not happening in the SubTree code. I hope all this was not very confusing 🙂
To summarize:
1) Your “RunningTask” I believe should be implemented as a Condition rather than an Action task. Doing this will allow it to work as you’d expect in the context of the Dynamic parent (and similar to how the SubTree behaviour works in your example BT).
2) I could add an option in the SubTree node to change the behaviour between Action-like or Condition-like.
Please let me know if the above clarify things up (or confuse things more) 🙂
Thanks!
Join us on Discord: https://discord.gg/97q2Rjh
Thanks. You have clarified so I understand why things are working as it is… Now I have to figure out how to handle to get it to run as I want :), because I showed you a really stripped down simplified version of what we need.