Behaviour Tree Tick Manual Control and Coroutines

AntL

Member
Hey there, I've a question about manually controlling behaviour tree update. In the attached screen shot is a behaviour. Pretty simple:

Capture.PNG
  • In the left hand sequence, it tests to see if the enemy is visible. If so, shoot!
  • In the right hand sequence, move to a position where the AI can see the enemy, then shoot them
I'm controlling this behaviour tick manually (it's a turn based game, so triggering the tick of the behaviour when it's enemy turn) like so:

C#:
    IEnumerator StartBehaviourTree()
    {
        if (BehaviorManager.instance == null) Debug.LogError("Behaviour tree instance is null");       
        BehaviorManager.instance.Tick(m_behaviourTree);

        while (m_behaviourTree.ExecutionStatus == BehaviorDesigner.Runtime.Tasks.TaskStatus.Running)
        {
            yield return null;
        }

        // For the moment we'll just give AI one move
        UseActionPoints(2);
    }

The issue is that the MoveAI action is bespoke and contains a coroutine, so when the behaviour is executed via a 'tick', MoveAI runs and yields (task return status returns 'isRunning') which ends the behaviour for that tick.

This makes sense, but I'm after some sort of mechanism that would allow the behaviour to be ran until it returns either a success or failure taskstatus return type. I'm thinking this could be achieved by how it's called - perhaps there's a way I can test to see if the taskstatus return type is running, but the behaviour tree isn't executing and then trigger another tick?

Thanks for any help!
Ant
 

Justin

Administrator
Staff member
The ExecutionStatus enum should reflect the current status of the tree so if a task is running then it should return TaskStatus.Running. Are you saying that's not the case?
 

AntL

Member
The ExecutionStatus enum should reflect the current status of the tree so if a task is running then it should return TaskStatus.Running. Are you saying that's not the case?
Actually, I think I've led you up the wrong path here as my issue lies somewhere else. To cut a long story short, the issue existed as OnFixedUpdate() wasn't getting called, which as I understand you must do manually when controlling the tick update. With that in mind I added this code and it's working as expected:

C#:
    IEnumerator StartBehaviourTree()
    {
        if (BehaviorManager.instance == null) Debug.LogError("Behaviour tree instance is null");

        // Ensure duplicates are set to count (we could change this in script per behaviour)
        BehaviorManager.instance.Tick(m_behaviourTree);       
        BehaviorManager.instance.FixedUpdate();


        while (m_behaviourTree.ExecutionStatus == BehaviorDesigner.Runtime.Tasks.TaskStatus.Running)
        {
            Debug.LogFormat("[BehaviourTree] Running Behaviour Tree");     
            BehaviorManager.instance.Update();
            BehaviorManager.instance.FixedUpdate();
            yield return null;
        }

        Debug.LogFormat("[BehaviourTree] Behaviour Tree stopped");
        // For the moment we'll just give AI one move
        UseActionPoints(2);
    }

With the above, I'm a little confused what BehaviorManager.instance.Tick(m_behaviourTree); does compared to BehaviourManager.instance.Update()?

Cheers
 

Justin

Administrator
Staff member
Tick will update an individual tree, whereas Update will tick all of the trees.
 

AntL

Member
Ok thanks - so how would I run the OnFixedUpdate for an individual tree that is triggered manually?
 

Justin

Administrator
Staff member
If you are ticking within FixedUpdate then the Update calls will be called during FixedUpdate.
 

AntL

Member
Sorry not quite following the explanation. My OnFixedUpdate is moving my rigidbody game object, while my OnUpdate is returning the taskstatus (which is set from elsewhere in the code).
 

Justin

Administrator
Staff member
If you are manually ticking the behavior tree within FixedUpdate then all Update calls will be executed during the FixedUpdate tick. The FixedUpdate callback within the tasks will not be called. This is because if the tree is being called manually then the FixedUpdate loop doesn't run.
 

AntL

Member
Yeah understood. So what I'm asking is how do I manually call FixedUpdate for one particular tree and not all trees (the only way I know how to call FixedUpdate on my current tree is by calling BehaviorManager.instance.FixedUpdate() which calls FixedUpdate on all trees) - if I've understood this correctly.
Cheers
 

Justin

Administrator
Staff member
There isn't a direct way - the best way would probably be to import the runtime source and modify the FixedUpdate method to expose the function. I can also add this to my list.
 
Top