godot-addons / godot-behavior-tree-plugin

Behavior Tree implementation for the Godot Engine as an addon in pure GDScript
MIT License
208 stars 19 forks source link

Direction for addon? #31

Open brandonlamb opened 4 years ago

brandonlamb commented 4 years ago

I'm curious to know from anyone who is/has/tried to use this, whether this node-based solution or a pure code-based solution would be better?

I'm finally getting back into some Godot coding (after like a year), and updated the two FSM addons (one with pushdown automaton), and I still wanted to come back and rewrite/update a behavior tree. I was debating a rust or C# implementation as well.

For my own use-case, I would more prefer a code-based instead of dragging nodes, and I assume it would be more performant (but not sure).

DagobertDev commented 4 years ago

It's possible to allow both node- and code-based creation of trees, the performance after creation should be equal.

C# sounds interesting, it's officialy supported in Godot and would allow using the plugin with Unity as well.

brandonlamb commented 4 years ago

One thing I see right away after coming back after a year, is I would probably apply some code style/standards updates, such as using PascalCase convention for script filename and class names. I think someone had gone through and added static typing, but if not I would add that too.

I wish there were a consistent convention for... "namespacing", reminds me of my PHP days WordPress_Post, WordPress_Page for class names to avoid clashes with common things.

aclave1 commented 4 years ago

Hey Brandon, I'm glad you've opened this issue, i'll give my feedback about the library.

Building a tree with the library using the existing godot node editor is slow. I was actually considering doing everything from code as well. One option would be to create a more integrated UI for building behavior trees, like the animation blend tree. Godot already has some components to create graph editing UIs.

brandonlamb commented 4 years ago

@aclave1 - interesting you bring up the graph editor as I did take and fork a repo that was doing this and start updating it. I do like the graphnode editing better than adding nodes via scenetree.

I feel like I dont have enough experience myself yet ACTUALLY implementing any game logic with either a FSM or BT to really know what im doing

aclave1 commented 4 years ago

I feel like I dont have enough experience myself yet ACTUALLY implementing any game logic with either a FSM or BT to really know what im doing

No time like the present! Maybe we need a more substantial demo project with player input so we can actually know how it feels to implement the game logic. It's not a full game, but it provides a space to experiment. I know I personally learned a lot from developing games, but also reading The FEAR AI paper. Though it's GOAP and not btrees, I still think it applies. FSM is for fine control of the character: animations, reacting to player input, etc. Btree is more for decision making: deciding which states to move to in which sequence to achieve a goal.

As for building out a node-based UI, I like to have something to point at so here's some screenshots of some existing ones image image

The main features they seem to all provide is:

Another thing I'd like to bring up is the issues mentioned in #19 - I'm not sure if the performance is as bad as is alluded to, but I think it's something that needs to be addressed. I've done just fine implementing actions that take multiple ticks. The key is to return the RUNNING status and use memory selector/sequence nodes. Since the composite nodes return their child's running status, there's a nice depth first traversal(which enters/exits nodes) to the currently running node.

fmgc commented 4 years ago

Hello,

New Godot & Behavior Tree user here, ~1 week :), trying to use BT's on a personal research project. This issue seems really on the right time.

Two wishes wrt the current status:

  1. A graphical editor, with the outlined features above would be amazing.
  2. A simpler "bridge" to the actor, concerning the implementation of actions and conditions.

Concerning the "bridge" to the actor point, I find the current solution a bit clumsy :(. Maybe I didn't understood well enough the right workflow? When adding an action or condition node it is required to override the tick method of BehaviorCondition or BehaviorAction. If there are "many" actions and conditions they become that (too) many files. In my particular use, each one simply calls a related actor method. For example,

extends "res://addons/godot-behavior-tree-plugin/action.gd"

func tick(tick: Tick) -> int:
    var delta = tick.blackboard.get("delta")
    return tick.actor.ask_waypoint(delta)

The result is that, while creating (and debugging) the tree, one is switching from file to file...

Why not let the implementation of actions and conditions tick be defined by actor's methods and take advantage of GDScript dynamic features (although "functions are not first-class citizens" one can use Node.call("function", args))?

The core of what I'm saying here can be illustrated with the following screen capture, from an experiment I made:

ilustration_edit

Sorry for the (quite) long, certainly naive, post.

aclave1 commented 4 years ago

@fmgc what you say makes sense. You do really have to create a lot of files to create any real AI. I think this is possible, when adding signals to a node, there's an editor which allows you to select which function should be called, I don't see why this couldn't behave the same way and reuse the godot code.

fmgc commented 4 years ago

Hi @aclave1,

Meanwhile, maybe there is a more elegant solution: Just extend bt_base with suitable classes.

For example:

extends "res://addons/godot-behavior-tree-plugin/bt_base.gd"
export (String) var actor_action = ""
# Leaf Node
func tick (tick: Tick) -> int:
    return tick.actor.call (actor_action, tick)

and

extends "res://addons/godot-behavior-tree-plugin/bt_base.gd"
export (String) var actor_condition = ""
# Leaf Node
func tick(tick: Tick) -> int:
    return tick.actor.call(actor_condition, tick)

On actor, actor_action and actor_condition must be the names of methods with a single argument, tick: Tick, that return an int.

I think that signals may not work well because nodes must return a status.

aclave1 commented 4 years ago

@fmgc that's a smart way of doing this, it doesn't even require support from the library.

I think that signals may not work well because nodes must return a status.

I was not saying to use signals to implement this, I was just pointing out an example of a UI that's able to pick a function from a class.

Rubonnek commented 4 years ago

@brandonlamb For what it's worth, I'd rather have a code-based implementation to avoid the node traversal and the memory overhead of just having nodes overall. I also think it would be more performant. Perhaps we could use something similar to CallbackDelegator, Behavior, and ResourceSet as presented by willnationsdev in this youtube video.

DriNeo commented 4 years ago

How did you notice that using the scenetree is slower, and to what extent please ? Keeping track of the nodes without anything graphic scares me. I need a solid reason to do everything in scripts.

Ciph3rzer0 commented 4 years ago

Based on what some people want here, you may want to check out https://github.com/fian46/addons-btree. It has a graph editor, with a drop down selector for functions that start with task_. With some basic functions like duplication and collapsing subtrees (but no way to collapse again easily after expanding). Unlike scenes, there's no easy way to copy subtrees between different trees.

Def worth checking out this channel where I saw it being used. It has a gui (make sure you click save (NOT CTRL+S, NOT ALWAYS GOOD ENOUGH) any time you even THINK about leaving the tree editor window. (Also I recommend adding in git regularly. I've had trees completely disappear) I routinely would get random crashes if I didn't save, then play (as opposed to playing which triggers a save before trying to execute).

I tried making editor plugins and I know how hard it can be; wasn't able to do what I wanted after weeks of trying. IDK if @brandonlamb has attempted the editor portion at all, but personally I think it's a waste of time unless someone already has experience working with plugins, or they document and support it better. IMO

IDK if nodes cause much overhead. I have a vague memory that the way GDScript is designed, that there is no cost (or next to no cost) over a normal reference. Sticking to the system means it's more intuitive for new Godot users.

I know every other engine uses a visual layout, but I honestly don't see why it's needed. It seems like more of a headache than anything. There is no real advantage to it over the scene editor. PLUS, think about the options that you have with the scene graph (which is why I came here after using fian46's solution above) are better. With scenes, I can package up behaviors into drag and droppable prefabs. So if I need the same behavior set in multiple places, I can duplicate and modify them, making them less error prone, etc.

The benefits of pure code is versioning. However, if it turns out that speed IS a factor, I see no reason why you couldn't "compile" a visual or scene graph at runtime to a pile of pure classes. I think the loss of flexibility of being able to add or remove behaviors at runtime would be a downside. I'm sure there are ways around it, but I'm considering, what if I want to model an agent being able to learn? Or add a new ability based on a pickup. I'm only a few days into this behavior tree stuff so maybe that's not ideal, so idk.

So, my own personal opinion, the best is scene based tree representation. I'm going to probably use the above tactic to call functions by string to avoid tons of unnecessary files. Ideally it'd be cool to have the same drop_down feature fian46's btree has, but I'm not sure that's possible as an editor export.

Unless I'm missing something, I just started using this library and I feel like I've wasted as much time learning about as I could have just wrote my own. I'm still failing to understand why some nodes chose to _execute() on their children and other's tick(). And what is supposed to be put in the enter() function. For example, the Wait node seems to completely not work if it's put under a child that calls _execute(), since that will call enter() which resets the counter. Add delta to tick btw. It just makes sense, right? The wait node sets up its own _process() which will run forever. It should be able to tick it's counter from the tick function with delta

I'd also like to see the ability to continue an action without fully evaluating the tree. I envision calling quick_tick() every frame and calling something like full_tick() to force the tree to evaluate from the root.