thepat02 / behaviourtoolkit Goto Github PK
View Code? Open in Web Editor NEWA collection of tools for AI Behaviour in the Godot 4 Game Engine!
License: MIT License
A collection of tools for AI Behaviour in the Godot 4 Game Engine!
License: MIT License
Ok so we have new Godot, what now?
Are we migrating on it with 2.0, if yes when (after waht PRs will be merged).
And do we make special version of 1.x branch for 4.2?
Yo :)
I've noticed that BT work on _process()
by default. For my use case I will need it to work on physics frame not idle, so I wanted to create PR with functionality to select between IDLE
and PHYSICS
frames processing as an @export
in BTree and FSM.
I poked at Beehave and their master
also has it now (althoug AssetLib version doesnt). I would probably implement it in similar way, although they don't provide delta
in tick()
so users while coding the leafs
will have to guess which process the Tree
is using.
Thata said, while checking the BT code I've noticed that you store current delta in the Blackboard
resource which is fine by me, but is there a reason to not provide it as a property in the tick()
?
Something like:
func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> Status:
return Status.SUCCESS
I think this would be more performant, easier to optimise for GDScript, less error prone from user perspective and easier for user to understand how to use the API.
I also think that default should be PHYSICS_FRAME_PROCESS
becasue BTree will most likely by used mostly to modify Actor
that is a CollisionObject2D
or CollisionObject3D
.
And if user would need to run his BTree or FSM for some visual stuff where he want the code to run on every IDLE
frame he will simply switch from default PHYSICS
process to IDLE
in the inspector. :)
What do you think?
Similar to #4
I know there will be a new example scene in the future, but I was curious of the setup of current version. It's kinda hard to read for a first-time user (since all nodes have a script attached, even though the script has no logic), but what I want to mention in this issue is that there are function calls which do not point anywhere and are dynamically cast.
On the FSMState "TransformIntoGhost" there is the code
func _on_enter(actor: Node, _blackboard: Blackboard):
# Make Transparent
actor.set_modulate(Color(1, 1, 1, 0.5))
actor.ghost_state_machine.fire_event("fully_transformed")
I cannot ctrl+click set_modulate either.
func _on_enter(actor: Node, _blackboard: Blackboard):
# Make Transparent
(actor as Actor).set_modulate(Color(1, 1, 1, 0.5))
(actor as Actor).ghost_state_machine.fire_event("fully_transformed")
The above is more intuitive imo, and its a codestyle I suggest for the future example scene. After all, the example scene is what convinces a developer whether to use or not
#37 mede me think - if customizable BTLeafs are good thing or is it better to granulate them more into more Atomic nodes?
My first design of LeafSignal only had one task to emit signal to drive code in other game systems built with composition in mind.
It was proposed to add ability to send signals from and Actor which is very usefull as well!
Te bo more coherent with LeafCall it also should support Custom nodes as well...
So my first issue is that adding extra functionality would add extra runtime calls for Leaves. With BT being used for complex behaviours of nodes. Usually used (but not only) for AI Actors, that in some games (like in mine) can have large numbers those calls might be in many use cases un-needed and called on every frame D:
Second problem I worry about is that it makes BTree less readable, user either will need to remember, check in inspector or add to nodes name information who the Leaf is calling.
My proposal is to split nodes like LeafCall, LeafCondition, LeafSignal etc. into more atomic nodes:
Aside from performance it has extra benefit of us able to add new icons for them that will describe compactly it's purpose in line with current Behaviour Tookit design. :) So no need for extra info in name, checking inspector, remembering stuff.
If we go this route we should talk how to desing icons. I would suggest combining nodes with some sort of generic mini-icon for Actor, Node, Blackboard.
For example LeafActorCall would be current icon with Small A or small triangle in the corner? Maybe also color code the mini-icon or the whole icon?
If approved I would gladly work on this refactor! 😃
If not, I would gladly make my own atomic Leaves for my project, because I will have a lot of actors in my game and I hope it to run on Switch CPU xD (a lot of mobs on the screen at the same time...)
Passing a actor is bad because the actor is of unknown type and in cases of built in scripts or scenes can't be typed.
Also if we rely on actors behaviors could rely on a variable or function that is not on that type of node.
This means that a behavior would either crash or fail in the case a node type is used that is incompatable
Consider one of the following...
Godot's design philosophy doesn't help.
I suggest adding the _on_enter(_actor: Node) function to leaf , composite and etc. Since this will make it possible to conveniently change behaviors or parameters in them.
Example:every time the behavior tree reaches BTRepeat, I need to write a number from _actor.rep in repetition and the same situation with LeafWait
BTSequence does not return a SUCCESSful status when the last action is successful. Currently it waits for the next tick to reset itself and report success.
While this doesn't appear to be a problem for trivial cases, when a child node of an FSMStateIntegratedBT that is configured to fire an event on success, the event does not get fired until the first task of the sequence has already run. This is particularly problematic if the first task is intended to check conditions based on the current state of the game world.
The 'minimal' scene setup:
finished
event on success.
finished
timeout
Ultimately what will happen is this:
I would have expected this sequence:
The offending lines of code appear to be in bt_sequence.gd:
func tick(delta: float, actor: Node, blackboard: Blackboard):
if current_leaf > leaves.size() -1:
current_leaf = 0
return BTStatus.SUCCESS
var response = leaves[current_leaf].tick(delta, actor, blackboard)
if response == BTStatus.RUNNING:
return response
if response == BTStatus.FAILURE:
current_leaf = 0
return response
current_leaf += 1
return BTStatus.RUNNING
I can put in a PR for a fix, but I really don't have any good way to know if doing so would introduce issues elsewhere. When I see a slightly awkward construction like this, I have to think there is a reason for it.
How would I handle input via behavior trees?
It would be nice if there was a place to ask questions and discuss behavior toolkit that didn't flood the issues tab.
Title speaks for itself. It's kinda hard to make loops rn. I know that classic BT doesn't have this but such feature seems reasonable
It would be nice if this was easy to use with C#
Some general purpose utility leaves for behavior trees would be nice to have. I'm not sure how abstract they can be made given the limitations of Godot's editor(e.g. no support for Variant @export properties).
I think 1 leaf for each node property type that can be tweened would be useful? So, TweenVector3
, TweenVector2
, TweenInt
etc.
Or you could maybe accomplish the same thing with a few Tween leafs for each primitive type in Godot:?
class_name TweenFloatProperty extends BTLeaf
@export var transition_type: Tween.TransitionType = Tween.TransitionType.TRANS_SINE
@export var ease_type: Tween.EaseType = Tween.EaseType.EASE_IN
@export var tween_property: String = "rotation:y"
@export var tween_value: float = 0.0
@export var duration: float = 2.0
var tween : Tween
func tick(actor: Node, _blackboard: Blackboard) -> Status:
_init_tween(actor)
if tween.is_running():
return Status.RUNNING
return Status.SUCCESS
func _init_tween(actor: Node):
if tween == null:
tween = get_tree().create_tween().bind_node(actor)
tween.set_trans(transition_type)
tween.set_ease(ease_type)
tween.tween_property(actor, tween_property, tween_value, duration)
For now BTree adds it's frame delta
to a Blackboard
to be accessed in a extended BTLeaf
script.
FSM for now doesn't provide frame delta
but it's probably a bug :)
Not sure if it have any advantage over providing delta
as parameter, it's quite cheap to add to a Blackboard
but still slower than direct parameter and less cluncy to retrieve and delta
between frames is very common thing to use.
Only reson to store it in Blackboard
would be to share it with other system, but BTree and FSM would update it every frame either way so this is not needed and I don't think anybody would want to change it in the middle of evaluating BTree or FSM. That would be a silly thing to do :D
Providing it directly in the method call property would be also much more intuitive for the user, and less stuff to learn from documentation for them.
I was thinking about changing API for tick()
and _on_update()
to:
func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> Status:
return Status.SUCCESS
func _on_update(_delta: float, _actor: Node, _blackboard: Blackboard) -> Status:
return Status.SUCCESS
Other thing maybe unrelated to this proposal (I can make new one if you wish).
Shouldn't tick()
be _tick()
?
So I have a pretty simple FSM with 4 states: Idle, Walk, FollowUntil (follow enemy until it's not in attack range), Attack.
I want to have an opportunity to make transitions almost from every state to every other state. And sometimes I want to configure some transition using scripts. But it turns out I have to make 4 (states amount) * 3 (other states amount) = 12 transitions. Looks pretty bad... And I have to make even more when I make new states. And it turns out we have geometry progression of transitions...
Yes, I know we can call switch_state()
on FSM to switch states. But it makes transitions uncustomizable. And mixing switch_state()
and events are kinda bad decision
First thing that comes to mind is to remove transitions at all and make function like _handle_transition(to_state: String)
in FSMState template. So you can process needed transitions using code
switch_state()
Ok. So the problem is "I want to change states from one to another and also have opportunity to customize some transitions". To solve this we can make switch_state()
the desired way to change states instead of fire_event()
. And in switch_state()
function we will seek for child transition that satisfies our logic and call _on_transition()
of this node if found
Consider converting behavior toolkit to use graph edit and resources..
Here are the pros of doing so...
Here are the cons...
Add automatic tooltips for buttons in the editor UI
Your add-on looks very impressive!
Do you plan to make some debugging and profiling tools similar to Beehave ones?
Currently every FSM/BT updates on every _process
tick. Add options for update pooling, lower/custom update rates.
When I open BT scripts they often are corrected by Godot and indentations are auto corrected from spaces to tabs. ^^'
I think we should stick to official conventions and use tabs for GDScript so there will be less issues and hassle with that.
Or maybe you use external editor and it had configured indents as spaces by default?
Implement a Simple Parallel Composite as shown in this documentation.
Just so its easier to find for those of us who are extremely good at things like freedom and eagles 🦅 but have for some reason decided to drop the letter u
from a bunch of words!
Releated to #21
I rly like GUI Toolkit for editing BT behaviours trees and I have idea how to improve it a bit.
Currently pressing Node buttons in Toolkit just adds the respective Node as a child of the selected Node in the Scene Tree.
My problem is this might be not exactly what I want and I have to re-organize Nodes by hand after, which is error prone and takes time.
Example, for Decorators I often woudl want to add them as a parent of the selected node. When adding BTLeaf to Composite nodes I would usually want to add them as next node in line.
I was thinking of extending the behaviour of the Toolkit UI when using keyboard modifiers like SHIFT, ALT and CTRL
Example:
CTRL + ALT + Click = Replace selected node with clicked node. (Double modifier for this one to be more safe from error.)
CTRL + Click = Swap selected node with clicked node in place and add selected node as clicked node child. (Nice for decorators and composites)
SHIFT + Click = Add clicked node as a next sibiling of the selected node. (Usefull for BTLeaf and FSMState so user desn't have to changle selection after editing current one)
To make this more disovarable and easy to remember we could add a strip with hints on the bottom of the Toolkit UI dock.
FiniteStateMachine
only processes one event per frame.
I'm not sure if this is a bug or if it is intentional, but it was certainly a surprise to me. I was expecting the event stream to complete its processing within a given _process_*()
callback. Ultimately this assumption led to some really wonky behaviour and/or delayed transitions as the queue backed up.
I can hack in a solution locally, but if this is intentional I'd rather not build on a hacked solution that breaks fundamental assumptions of the library.
I'm not sure what the intent is here. Could I get some clarity?
Currently working in progress.
Needs complete rewrite or refactoring.
On Windows 11, Godot 4.2.1, I started a new project, imported the plugin via the AssetLib, and see the following errors. It doesn't look like I can use the plugin either, when attempting to create a new node, I'm not seeing any of the types.
Godot Engine v4.2.1.stable.official (c) 2007-present Juan Linietsky, Ariel Manzur & Godot Contributors.
modules/gltf/register_types.cpp:63 - Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported.
--- Debug adapter server started ---
--- GDScript language server started on port 6005 ---
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Add.svg-b8640946cfefb2cca92e911950570ce6.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Blackboard.svg-99aad113ca567e93eaff49dbc3f77175.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTBehaviour.svg-afa2230ba3707fb234ee9ca9709aead7.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTComposite.svg-412f185ff8fece951b022e38ba5a7c23.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeIntegration.svg-9584b35e5fb929ba98b0a02fb58c84cb.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeRandom.svg-c18a16f3d816da0799f1e1aa9211e913.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeRandomSelector.svg-0512a3de5f88f3ca2a3841f24ac587eb.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeRandomSequence.svg-190695524eac4f2c5cfb58aafe93cfbb.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeSelector.svg-c3f04299814d16ef776f826287ac3a80.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTCompositeSequence.svg-1ad4ef7ed8c22330cea4e8cfd8a06ca5.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecorator.svg-a54f8ee76d81f0aada9ae7822177699f.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorFail.svg-972bf6cae2c89e592f736f7d1eb80693.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorLimiter.svg-83cc68457edd2d4d6c5a47d3d203e0d1.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorNot.svg-db308d1bbf533b47c32d25af8f80de5d.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorRepeat.svg-a5c5ef593dd674d9da616e81f0a70c8c.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTDecoratorSucceed.svg-5ae36e790992843eb08f1aaf9f19c05c.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeaf.svg-394bab6a37a064c62d9109929dce527d.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafCall.svg-0259ff3dd7a45558b84cab026665c30a.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafCondition.svg-555fd5d45040620aff94ac7db2b23380.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafIntegration.svg-974541a1d51285a695521e9140e5e19a.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafPrint.svg-f6f2d7d14c8ddb0bc684a53d76e39548.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafSignal.svg-f98548f09cd6423647caa2b3e0b830a4.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafTween.svg-72f39562bcea332854ab58b3a62fb7e4.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTLeafWait.svg-f454910626932d116ba56d8724164bd1.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTRoot.svg-eacfbd4d2762cc392094c55ff923e78c.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/BTSimpleParallel.svg-8546d47eb70a7b37aaad191b53aafa06.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/EditorBTRoot.svg-6b6916705e3fa73f7ffe40a77ed65841.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/EditorFiniteStateMachine.svg-e8608d1bbb81a21982b3327f762e9126.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FiniteStateMachine.svg-e73522dd5cc41a5534bd00f4347b88cf.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMState.svg-5a4ec18f1220b396d81ac0c29c407dbb.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMStateIntegration.svg-a2b58c754cdf4634ea934415452099ad.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMStateIntegrationReturn.svg-3b3b086bb57c5145bc7be34e441fba59.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/FSMTransition.svg-03add443dbedecc72086260f8244e911.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Gear.svg-4bd0640c31f268fb47db19b3b4730128.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Help.svg-b760ac21373bc62f0a4da09a57e2f015.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Logo.svg-8cfecbbf805a6ab0b538dbc1ba0eccfd.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/placeholder.svg-d1f5342e31d8125f82f8e7322e2c8be9.editor.meta'
Missing required editor-specific import metadata for a texture (please reimport it using the 'Import' tab): 'res://.godot/imported/Search.svg-46c789b409eba86b5d04be6ddccfe69c.editor.meta'
Tween isn't very useful due to the fact that a blackboard variable can't be used.
Consider adding the ability to tween to an exiting blackboard value
It would be a great feature to use value from blackboard cause it's not cool to have hardcoded value or set value from other leaves/scripts
The Status
enum in the BTBehaviour
class should be renamed into BTStatus
or StatusBT
, which will cause extensive renaming in the codebase.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.