question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussing Behavior Trees

See original GitHub issue

I’ve opened this to discuss behavior trees API enhancements.

@implicit-invocation Resuming discussion https://github.com/libgdx/gdx-ai/pull/4#issuecomment-56509640 … Not sure why you don’t like the XML format, but I think that it has some advantages:

  • comments are supported which can be really useful
  • it’s more powerful than json or any inline tab-based format.
  • being it a standard format, external tools like editors (written in any language) can easily read/write a behavior tree.

So I’m playing with the XML format just to see what can be done. Currently I can successfully load a behavior tree from this file:

<BehaviorTree>
  <Import task="com.badlogic.gdx.ai.tests.btree.dogtasks.BarkTask" as="Bark"/>
  <Import task="com.badlogic.gdx.ai.tests.btree.dogtasks.CareTask" as="Care"/>
  <Import task="com.badlogic.gdx.ai.tests.btree.dogtasks.MarkTask" as="Mark"/>
  <Import task="com.badlogic.gdx.ai.tests.btree.dogtasks.RestTask" as="Rest"/>
  <Import task="com.badlogic.gdx.ai.tests.btree.dogtasks.WalkTask" as="Walk"/>
  <Root>
    <Selector>
      <Parallel>
        <com.badlogic.gdx.ai.tests.btree.dogtasks.CareTask urgentProb="0.8"/>
        <AlwaysFail>
          <com.badlogic.gdx.ai.tests.btree.dogtasks.RestTask/>
        </AlwaysFail>
      </Parallel>
      <Sequence>
        <Bark times="3"/>
        <Walk/>
        <Bark/> <!-- times defaults to 1, see BarkTask source code -->
        <com.badlogic.gdx.ai.tests.btree.dogtasks.MarkTask/>
      </Sequence>
    </Selector>
  </Root>
</BehaviorTree>

I added the “Import” tag to improve readability. It allows you to use the given alias in place of the fully qualified class name of the task. Actually Selector, Parallel, etc… are predefined imports. Also, the “as” attribute is optional, meaning that the simple class name is used as the alias, i.e.

  <Import task="com.badlogic.gdx.ai.tests.btree.dogtasks.BarkTask"/>

creates the task alias “BarkTask”. Also, I added task parameters, see urgentProb in CareTask and times in BarkTask. The attribute value is parsed according to the type of the corresponding field of the task class. For example, urgentProb is a float and times is an int. Supported types are: int, Integer, float, Float, boolean, Boolean, long, Long, double, Double, short, Short, char, Character, byte, Byte, and String.

Of course, we can maintain both formalisms as long as they have the same structural features. I mean, unlike task parameters, imports are just a syntactic sugar so they are not mandatory for the inline tab-based formalism.

I think we can use a “btree” branch in order to experiment with BT improvements while keeping the master branch clean.

Issue Analytics

  • State:open
  • Created 9 years ago
  • Comments:143 (98 by maintainers)

github_iconTop GitHub Comments

1reaction
mgsx-devcommented, Dec 30, 2016

I don’t know if it’s the right place to post but I have some suggestions :

First of all I think current API is complete specially with guards and dynamic guard selector, I personally always found a way to implement logic with provided generic tasks without hacking a re-code things (nice job BTW).

My concern right now is about pooling strategy :

  • It seams impossible to use LibGDX Poolable interface with Task because of API conflicts (both reset methods have same signature but not the same contract). The only way I found so far would be to rename Task.reset to Task.resetTask and let Task implements Poolable interface. This change the current API.
  • there is no way to remove children from task in order to recycle. Note that possibility to remove children would be a useful feature for editors as well.
  • For now I only recycle entire trees (based on archetype name) but this lead to 2 drawbacks :
    • in context of editor, pool have to be cleared to reflect changes on edited tree archetype which make pools almost useless.
    • in a “game context”, it work well if you have few tree archetype and a lot of instance of them but with a lot of tree archetypes, pools may retained lot of big trees which may not be reused at all.

My conclusion is that pooling strategy is game specific : recycle whole trees, recycle tasks, don’t recycle is a design choice. But we need a mechanism to allow individual tasks recycling though and I think using Poolable interface is the best choice we have.

@davebaol What do you think ? Did you faced this problem ? I could provide a PR if you don’t have time to implement it but I need your approval first.

0reactions
davebaolcommented, Jan 2, 2017

@mgsx-dev

@davebaol What do you think ? Did you faced this problem ? I could provide a PR if you don’t have time to implement it but I need your approval first.

I’ve never needed to instantiate/destroy trees in game. I always do it during the initialization phase of the level, but I do recognize your use case. So, yes, PR is welcome. 😄

It seams impossible to use LibGDX Poolable interface with Task because of API conflicts (both reset methods have same signature but not the same contract). The only way I found so far would be to rename Task.reset to Task.resetTask and let Task implements Poolable interface. This change the current API.

Sounds good to me

there is no way to remove children from task in order to recycle. Note that possibility to remove children would be a useful feature for editors as well.

Yeah, this would be an interesting feature. Just notice that when you remove a child the parent task MUST update his own internal status accordingly. This operation is task-specific, of course.

My conclusion is that pooling strategy is game specific : recycle whole trees, recycle tasks, don’t recycle is a design choice. But we need a mechanism to allow individual tasks recycling though and I think using Poolable interface is the best choice we have.

Couldn’t agree more

Read more comments on GitHub >

github_iconTop Results From Across the Web

Introduction to behavior trees - Robohub
In this post, I will introduce behavior trees with all their terminology, contrast them with finite-state machines, share some examples and ...
Read more >
Designing AI Agents' Behaviors with Behavior Trees
In this post, I will explain the Behavior Tree and implement it on our Pacman to show that Behavior Tree is easy to...
Read more >
Behavior Trees - Introduction - Awaiting Bits
Behavior Trees are an easy way to model and represent some kind of behavior. Each tree consists of composite nodes (sequences, selectors and ......
Read more >
Behavior trees for AI: How they work - Game Developer
An introduction to Behavior Trees, with examples and in-depth descriptions, as well as some tips on creating powerful expressive trees.
Read more >
What is a Behavior Tree and How do they work? (BT intro part 1)
In this video lecture we explain what a Behavior Tree is, how it works and its advantages in terms of modularity, hierarchical structure, ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found