Proper way to perform conditional logic

dangoyette

New member
I'm struggling with how to structure my Behavior Tree to allow for complex conditions without interrupting long-running actions. What I'm finding is that any Success in a Conditional node will trigger a conditional abort on the currently running task, even if the rest of the branch doesn't result in Success.

Here's a simple example:

ConditionalAborts.JPG

On the left, we have a pair of Compare Shared Bool nodes, with inverted comparisons. It's impossible the them both to return Success. One will always return Failure, regardless of the value of Val1. When I start running, one of those two will fail, and we'll happily enter the "Idle" node on the right, which just returns "Running" indefinitely, and the tree is stable.

However, if I toggle the value of Val1, the "Idle" node will be aborted, as the results of "Val1 is TRUE" and "Val1 is FALSE" will switch output. However, the value of their parent Sequence remains Failure, since one of the two will definitely fail. But the damage has been done. "Idle" has been interrupted, and will restart. If "Idle" were some other long-running process, this becomes a problem.

I thought maybe my approach to evaluating conditions was just not the right way of going about things. I instead tried replacing the Compare Shared Bool with a pair of "Conditional Evaluators", which themselves perform the Shared Bool comparison, one against True and one against False. Although this runs on the first tick, it doesn't reevaluate when "Val1" changes, even if I choose "Reevaluate" on the node. Someone reported this issue in this thread: (https://www.opsive.com/forum/index....-again-while-another-subtree-is-running.1505/) However, there wasn't a clear answer. Instead, the user was told to use plain old conditional nodes.

Is there another way to structure my logic above such that "Val1" can change without aborting "Idle"? I realize I could put all of my logic into a single custom node, but that means I can no longer compose my tree from small, reusable nodes.

So, to recap, I was hoping to be able to chain together conditional nodes to control aborts. For example, "Perform X if A, B, and C are all true, otherwise perform Y". The way it works now, if "Y" is running, and any of conditions A, B, or C return Success, "Y" will be aborted, even if A, B, and C aren't all true. This results in Y immediately restarting, rather than remaining in a continuous running state.
 
To clarify the issue with Conditional Evaluators, see this tree:

ConditionalAborts2.JPG

If I start this off with Val1 being tree, the left side of the tree evaluates, and "Log" is called. If I then change "Val1" to false, the right side of the Sequence results in Failure, and the "Idle" node begins to run. However, if I then set "Val1" to true again, the "Val1 is TRUE" conditional evaluator doesn't reevaluate. It remains false forever, never changing again.

So, it seems like Conditional Evaluators don't work as I would expect. It seems they can't change from Failure to Success, only the other way. Note that I have "Reevaluate" checked, and my Behavior Tree has "Restart When Complete" checked.
 
For more than one conditional evaluation you'll need to join multiple conditions into a single task. Conditional aborts trigger when the task changes from success to failure or failure to success. By joining multiple conditional blocks in a single task you'll ensure that the conditional aborts on trigger once.
 
Okay. So that means I'll have to author additional that compose the functionality of various other tasks. For example, if I had two Conditionals, "Is Facing Target" and "Is In Melee Range", and I want one branch to be activated only if both are true, I'll need to write a new custom Conditional called "Is Facing Target And Is In Melee Range".

Any idea if the Conditional Evaluator issue is a known bug? Or is there some trick to getting it to reevaluate? I suspect, though, that perhaps a Conditional Evaluator would still trigger an abort just like a normal conditional, so I probably can't approach this by chaining multiple conditional evaluators together and hoping for an abort to only take place when when they all return success.
 
Any idea if the Conditional Evaluator issue is a known bug?
The conditional evaluator will only reevalute when the decorator is active - it doesn't go outside the local branch scope like conditional aborts do. If reevaluate is deselected the conditional evaluator will only evaluate the conditional task once when the branch is started.

so I probably can't approach this by chaining multiple conditional evaluators together and hoping for an abort to only take place when when they all return success.
That's correct.
 
(for those who come here from google)
Now we can use "Stacked Conditional" Task to do that. (right?)
I've been stuck by the same question for a long time, until I have a try to look at those conditional tasks I can choose from, and found that there is a "Stacked Conditional" in the newer version, looks very fit with this scene.
 
Yes, that's correct :)
But I find this question:
I have a conditional task which has reference task in it , then I add it to a stacked conditional task, and I cannot set reference task for it in inspector.
I wanna do that for cooldown time check, like what Austin do in the thread: Help with creating a "Cooldown Timer" task.
Indeed, there is a built-in "Cooldown" task, but its behavior seems not what Austin and I need in that thread.
A basic sample of what I'd like to do: the enemy would do some thing when player is in some range, and the cooldown timer of enemy is over, roughly like below:
1650350005770.png
1650350453230.png
Of course, the checking sequence should be a Stacked Conditional to break the Idle task
However, if adding Cooldown Check to a Stacked Conditional, I cannot set its reference task to Cooldown Start, and now I'm confused...
1650350414078.png

Any help would be appreciated!
 
I can look at adding support for linked tasks in the stacked tasks. Right now you can do something similar through code using BehaviorTree.FindTask so you at least have a workaround.
 
I can look at adding support for linked tasks in the stacked tasks. Right now you can do something similar through code using BehaviorTree.FindTask so you at least have a workaround.
Hi,
Have tried the workaround, but when I completed my prefab edit and went back to the scene view, the whole behavior tree crashed to empty, and some errors showed up.
1650451545247.png
To recover my work today, I have to edit my crashed prefab as text, find the Stacked Conditional node and delete it. (Thank god!)

I think it may be caused by my CooldownCheck code, which still contains a Task type field. So I tried to delete the Task type field in it and only use Task type in expression. And it works like a charm.
 
Top