Architecture for behaviour trees with scheduled tasks [SOLVED]

Hi dear JGO :slight_smile:

I am starting to work with behaviour trees. I think i’ve got the rough architecture of the behaviour trees (BT’s from now on) down, but i am struggling with a key concept that i guess, i didnt understand right in the tutorials.(http://aigamedev.com/open/article/behavior-trees-part1/)

EDIT: Please refer to my second post, which explains my problem/question quite a bit better. Thank you very much!

The tutor speaks about a lookup table, where you can store ‘goal oriented behaviours’, the more modular the better and a task scheduler.

Now my question(s):

  1. Should an actor/entity always have a BT assigned to it + have some kind of node to process a task from a list, or,
    should one iterate the scheduled tasks and pass a BT instance to the actor and remove the BT instance from the actor upon SUCCESS/FAILURE/ERROR?

  2. Would a scheduler, literally have instances of BT’s as the ‘task’, and just pass that tree to an actor? Or would a task be a data structure that just describes what sort of BT it is?

  3. How would one pass a task to an actor that already has an active BT asigned to itself? I guess one could dynamically append/remove BT’s in the existing tree, but that seems like a bad idea to me.

I think, that an actor should always have a BT asigned, but i don’t know how to integrate a task from a list into a running BT, which will then have to be removed/appended, from a structure (BT), thats where i would loose all the control/advantage of pre-designed behaviours.

Need some help :slight_smile: Thank you very, very much in advance!

I haven’t looked at your link so I’m not quite following your question. BT’s aren’t one thing, but a class of things. Also not know what you want to do with your AI makes the questions hard. But it looks like you’re missing an important point. BT’s are always (logically) run from the root down. This is important, so “remove the BT instance from the actor upon SUCCESS/FAILURE/ERROR” doesn’t make any sense unless I’m misunderstanding this point.

Hi Roquen :slight_smile:

What i want to do with the Ai:
Imagine a game like Prison Architect/ Rimworld etc.
The player enters tasks to do on certain entities, this can be whatever: remove a block; cook a meal; fetch and entity and bring to another place …
So basically 100% tasks, but in case there isn’t any task, fallback to something else.

Quoted from Roquen:

[quote]This is important, so “remove the BT instance from the actor upon SUCCESS/FAILURE/ERROR” doesn’t make any sense unless I’m misunderstanding this point.
[/quote]
I know, but thats what i mean. From what i understood the actor always has one BT instance to run, that has been predefined(and will never be changed), from the root to the one that is running, thus, changing this architecture by adding/removing tasks would be cumbersome.

But, which options do i have left, respectively, how is it done in and ideal/professionnal way?

The only option I see, then, is to have a prioritized list, with tasks(In this case a BT instance), which are then passed to a certain actor. So that the new BT/Task replaces the old BT/Task, thus, not having to modify a running behaviour tree.(My previous post question nr 3))

Example:
b[/b]TaskManager:Assign BT to actor --> b[/b] actors runs BT until FAIL/SUCC/ERR --> b[/b] Mark Task as ‘done’ --> b[/b] TaskManager: remove marked task, and assign another BT to actor

So you never ‘change’ a Behaviour, but instead assign another one?(I guess that defines my question even more)

I hope the issue is a little more clear now, thank you so much for trying to help, i feel like i am ‘dancing on the surface’ with these behaviour trees at the moment :slight_smile:

I don’t know the games you’ve mentioned, but all you need is a sequencer node. Game wants to add a task to a specific entity…write it to it’s blackboard. The sub-root of “perform task” is a sequencer, first is handles any explicit tasks running or needing to run (returns RUNNING if so or SUCCEED if none or complete). The second handles any default tasks.

Please apologize me for the late answer Roquen.

I didnt even think about a ‘task-node’ in this way, i’m still not 100% groking the whole idea.
And effectiveley you are right about writing data to the blackboard, and nodes only reading from there. Thank you very much for putting me in the right direction!

I have another question if you don’t mind :slight_smile:

When the root node receives a state from it’s child (SUCC/FAIL/ERR), do you then reset the whole tree?, i.e, reset nodes to their initial state and then tick the tree like the first time?

Thank you very much again!

Actually I should have said selector node above…you can use a sequencer but selector is logically better.

Maybe you should play with an existing library to get a feel for it before writing your own. I’ve seen some reasonable BT tutorials but I’m not finding them from a quick glance at a web-search. Maybe peek at this one: http://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php which mentions using a java library that I’ve never looked at.

I’m being dumb this morning so I don’t understand what you mean by “reset” when the root gets a result. The root gets a result every tick so in the normal meaning of reset, then the answer is no.

I will maybe use a library to play with for a couple of days, but first i really like to get the basics down.
Also, i read the post on Gamasutra multiple times, which is great, but looses the great detail it ha in the beginning very quickly unfortunately.

As a reference for anybody else that looks at thiss topic:
Java Script based Behaviour tree editor: http://behavior3js.guineashots.com/
The explanation and implementation of the previously listed editor: http://guineashots.com/2014/07/25/an-introduction-to-behavior-trees-part-1/

Quote Roquen:

[quote]I’m being dumb this morning so I don’t understand what you mean by “reset” when the root gets a result. The root gets a result every tick so in the normal meaning of reset, then the answer is no.
[/quote]
If you have the time to check this post about BT’s: http://obviam.net/index.php/game-ai-an-introduction-to-behavior-trees/
You don’t need to read the whole thing! Then check for ‘reset’ in the browser, so you get to his explanation/code that resets the node.

Lets say you have a sequence:
Sequence
/
/
/
/
/
‘Searching’ ‘Attacking’

1a) ‘Searching’ is set to RUNNING and stays in that state until the enemy is found
1b) If the enemy has been found, ‘Searching’ is set to SUCCEED
2a) Sequence gets SUCCEED from ‘Searching’ and checks if there is another node to be run after ‘Searching’
2b) If there is another node, initialize that node and set that node to RUNNING
3a)Attacking is doing it’s thing, and return SUCCES if enemy has been attacked and FAIL if not(whatever)
3b)then the Sequence fails or succeeds

But then you want the actor to keep that behaviour up, but for that you need the ‘Searching’ and ‘Attacking’ nodes to be reset:
Reset: -> initialize (random values || get data from blackboard etc.)
-> set the state to RUNNING

If you leave the node in the state they returned, you can not just ‘use them again’, since the are either FAIL/SUCC/ERR

Sorry to make it so long, i hope you get the idea, need me some coffee, i wish i could buy you some too for your time and efforts :stuck_out_tongue:

I couldn’t find the description of ‘reset’ in the provided link…am I missing it or is it the wrong one?

The running of a sequence node’s tick does not have to depend on any results of the previous tick. BT’s can be structured in many different ways. As a class based example one could do something logically like this (I’m ignore putting state data on the blackboard…and I’m just typing this so beware):


public abstract class BTNode
{
  int state;
  
  abstract void reset();
  abstract void terminate(int state);
  abstract int  update();

  public int tick()
  {
    if (state != RUNNING) reset();
    state = update();
    if (state != RUNNING) terminate(state);
    return state;
  }
}

This way each ‘tick’ automatically handles the implementation choice such as you’ve mentioned…assuming I’m following you.

I realize that ‘everybody’ does handle the behaviour trees a little different.

[quote]This way each ‘tick’ automatically handles the implementation choice such as you’ve mentioned…assuming I’m following you.
[/quote]
Your snippet is what i meant, you were following correctly :slight_smile:
I was confused because some documents didnt even mention about what happens when a node returns a state, i.e, reseting and the like.

You helped me very much to understand 2 details of the technique better, thank you so much for your patience!

Greetings and all the best!

I wish i could give back more than just a virtual medal :stuck_out_tongue:

I’d pass on this reset based notion. It doesn’t help you define behaviors, adds extra state, state manipulation and runtime costs.