Simple text based behaviour tree

Hallo,
while there are several behaviour tree plugins in the Asset Library already, I wanted to have something simpler and quicker to use for prototyping. This is why I wrote this GDScript that should cover most usecases. The tree can be created either by using methods directly:

Screenshot_1

…or by parsing a text file:

Screenshot_2

Overall the script expects the user to know what they’re doing; and the code is not thoroughly tested, so if there are any bugs I’d be happy about any reports. A simple video showing it in action:

The code is on Github:

6 Likes

The behaviour tree supports dynamic parameters now even when constructing the tree from texts (prefix arguments with $ for that). This is probably super expensive performance-wise because you’re basically calling Callables inside a Callable inside a Callable, but I guess it’s okay for testing stuff.

1 Like

If you create a behaviour tree via text, the script now also accepts a tree node, which either (at the root) creates a sub-tree, or (inside a tree) uses that sub-tree by inserting it. If there’s any interest I would make a simple example for this.

I also added the decorator node ignore, which overrides the result of its child so the result is basically ignored by the parent decorator or composite node. And there’s the nothing node now, works a bit like pass in GDScript.

And of course there were some bugfixes.

1 Like

Wonderful job! I do struggling for write a node based behavior tree a lot. I think this text-based behavior tree can save runtime memory usage to a certain extent.

I roughly went through the code. Here are some suggestion for my point of view.

Scalability

Insted of mannelly define funciton like set_next_pos or walk_to_next_pos, how about use Expression to evaluate those function you write in the text.

For example if I want set a patrol position, instead of write set_next_pos, how about write somethink like:

set_actor_property(property_name: String, right_expression_text: String)

And you probably want customize the parse process of the property name since the GDScript always passed by value.
In this case:

#Vector2&Color could be some other function call or other thing you can get access base on the actor
set_next_pos → set_actor_property(next_patrol_position, “Vector2()”)
change_color → set_actor_property(color, ”Color(r, b, b)“)

Debug

Typically debugging takes 80% of my time writing the behavior tree, and it’s important to visualize it and make it simple, especially if your code is very extensible, that will make the behavior tree only executes a very little amount of the code once and once again, and breakpoints just don’t seem like a very desirable way to debug.

Hey, thanks for the feedback!

I appreciate the suggestion to use expressions for the parameters. I might add an option to use those with another prefix. I don’t think I want to use the Expression class for everything, this feels expensive.

What I definitely wouldn’t want is to change how the tree uses manually defined functions. I find this is the strength of a good behaviour tree, using expressive names. Stuff like set_actor_property(next_patrol_position, “Vector2()”) is verbose, especially as the example function set_next_pos could do much more stuff, like changing the actor’s animation, play a sound effect, etc. If you want to change properties directly it feels like a behaviour tree is the wrong way. You overcomplicate things for the sake of flexibility.

Also be aware that the (simple) text parsing in my script was added as a bonus, kind of. The native way is to add the nodes to the tree directly.

Regarding debugging, the tree script already has a method called generate_string(). If you call it with rich_text set to true and feed it to a RichTextLabel, as seen in my little video, you should have a good overview what the tree is doing.

This looks interesting. Reminds me of PandaBT, which was pretty cool.

Yes, I like PandaBT too, and it definitely was the inspiration for the text parsing.

The behaviour tree script now supports expression evaluation when parsing the tree from a string (put the expression inside curly brackets). Example:

tree 'CHANGE_COLOR'
	repeat
		sequence
			_change_col
			wait {1.0 / 3.0}

parallel
	repeat
		sequence
			_find_pos
			_go_to_pos ${0.5 * _speed}
			wait _wait_time
			say ${['Waiting!', 'What now?', 'Onwards!'].pick_random()}
	tree 'CHANGE_COLOR'

becomes

Screenshot_3