Conditional aborts not working as I expected in hierarchical setup.

snarlynarwhal

New member
I am having trouble setting up my behavior tree and I think it's because I do not fully understand how hierarchical conditional aborts work.

Intended Behavior

If an enemy is within `Buffer` units from their target, the enemy should back up (Flee to `Buffer` distance) before attacking. In this case, the Observer enemy should back up 3 units before firing it's laser beam, but it does not (you can see the player character's blue hair behind the Observer). It works as intended 90% of the time, but occasionally, it gets "stuck" in the following scenario:

Unintended Behavior

Occasionally the enemy gets "stuck" next to the target and does not back up. Instead it continues to attack without backing up (Fleeing to `Buffer` distance).

Capture.PNG

This portion of the behavior tree handles attack. `Buffer` that defines how much space to leave between themselves and the target. The leftmost branch (`Inverter` + `Check Distance`) makes sure that they're not within `Buffer` distance of the target. If they are, they flee to buffer distance in the middle branch (`Sequencer` + `Check Distance` + `Flee`). The rightmost branch makes sure they're still in range before attacking (`Sequencer` + `Check Distance` + `Attack Target`).

Capture1.PNG

My Understanding

From what I understand from conditional aborts, I would expect the entire left branch to continue to be re-evaluated in the background. I would expect the `Selector` to start with the leftmost `Check Distance`, which would return `Success` since the enemy is within `Buffer` distance from the player. Then the `Inverter` would flip this to a `Failure` causing the `Selector` to go to the `Sequencer` (middle). This second `Check Distance` is the same as the first, so should also return `Success` which should finally lead to the `Flee` task. Again, it functions like this most of the time. Not sure exactly what causes it to get in the "stuck" state.
 

Attachments

  • 1584669967660.png
    1584669967660.png
    91.7 KB · Views: 4
I can't see anything wrong with your logic. Can you send a repro scene to support@opsive.com so I can take a closer look at it? I have a unit test that looks sort of similar to that so I'd like to figure out what's going on in your case.
 
Just reposting my findings so others can see:

Conditional aborts trigger when the abort status changes. In your screenshot it does look like the task is being reevaluated, but because their previous return status was success they aren't going to trigger an abort. You'll likely need to restructure a tree a bit in order to allow the conditional tasks change trigger status.
 
Thanks for the info! I wanted to share my updated tree in case someone else runs into the same problem:

1584743295603.png

The `Selector` first uses `Check Distance` to see if it needs to `Flee`. If it is within `Buffer` distance, it will `Flee` to `Buffer` distance and then return success. The topmost `Until Failure` makes sure this branch gets re-evaluated despite succeeding.

Now, since the enemy just finished fleeing, the leftmost `Check Distance` will return false causing the tree to go the right `Sequencer` branch which attacks the target if it is within range. If the target is not within range, this too fails, and the branch exists altogether.

If, while attacking, the target gets too close, the leftmost `Check Distance` will return success and abort the `Attack Target` task in order to enter the `Flee` task.
 
Hello. I want to tap into the question.

This is my tree:
1585667492628.png

What I'm currently trying to achieve is to have two main states: Aggro (right branch) and Patrol (left branch). Within Aggro state I want to have 3 substates: attack (with condition that target is within range), chase (with condition that target is reachable) and aggro idle (a fallback behaviour when enemy still should show it's aggroed but it cannot do anything so it's just "standing still and being mad").

For most part this works as expected. Issue I have is with the wait behaviour for the aggro fallback.1585667761101.png

Issue is that this behaviour is not interrupted by conditions in other aggro states. To my understanding I could achieve what I want if I replicate all conditions under the fallback aggro sequence. I don't want to do that because of maintenance - I want to experiment with behaviours and maybe expand the tree which means I could easily forget to replicate conditions that were changed in other parts of the tree.

Is there a smart solution to this?
 
I would restructure your tree so patrol is on the right instead of the left, similar to this tree:

 
Thanks Justin. Video in link helped me found an error in setup. I needed to set abort type to lower priority in chase target branch (middle state of aggro branch). Now enemy is responsive.

1585747783616.png
 
Thanks for the info! I wanted to share my updated tree in case someone else runs into the same problem:

View attachment 2506

Not a big fan of this approach. Why don't you implement "check distance" logic inside Flee (Attack Target) code? With a distance parameter.

C#:
using BehaviorDesigner.Runtime.Tasks;
using UnityEngine;

namespace AI.Behaviors
{
    public class Flee : Action
    {
        [SerializeField]
        private float fleeDistance = 3f;

        public override TaskStatus OnUpdate()
        {
            //use sqr distances
            if (enemyDistance < fleeDistance)
            {

                //flee

                return TaskStatus.Success;
            }

            return TaskStatus.Failure;
        }
    }
}

To me it looks much better: only 2 simple nodes, instead of 6 nodes connected with obscure abort mechanics. And also, you control your flee distance right in the Flee node, not in some outer node. Am I missing something? :unsure:

444.PNG
 
Last edited:
Am I missing something?
No, that would also work :) Similar to programming everyone has their own way of doing things and I think that as long as the behavior tree is working as you want it to then you're doing it correctly. A few extra nodes won't hurt anything.
 
Top