|
1 | | -# godot-behavior-tree |
2 | | - |
3 | | -A GDScript implementation of a behavior tree for game AI, based on native Godot nodes and using the built in scene tree editor. |
4 | | - |
5 | | -C# VERSION -> https://github.com/MadFlyFish/godot-behavior-tree-csharp |
6 | | - |
7 | | -INSTALLATION |
8 | | -- Copy the 'addons' folder into the main directory of your project. |
9 | | -- Enable the plugin from project settings, THEN RESTART Godot, otherwise it will not recognize the new classes (that's a bug of the engine). |
10 | | -- Optionally, you can also drag the bt_example folder into the main directory of your project. |
11 | | -- To see the example working, run the agent.tscn scene. The ex_behavior_tree.tscn scene is an example of how the tree is built. |
12 | | - |
13 | | - |
14 | | - |
15 | | -INSTRUCTIONS: |
16 | | -- Click the node creation icon. You should see new nodes available (if you don't, restart Godot). You must use a BehaviourTree as the root node, which should have only a single child. This child can be any of the nodes under the BTNode category, which all inherit from the BTNode class. |
17 | | -- After creating a behavior tree, you must specify who is the owner of the AI (the Agent) and what Blackboard is being used. Blackboards can be put anywhere (given it is outside the tree), and even shared among different trees. The system is flexible enough to allow you to decide how and when to update your blackboard data. For example, you can make a plain Node with a script that handles updating the blackboard, eg. with signal callbacks or even in process(). Or you can do it from anywhere else, even from inside the tree, just make sure to design things in a way you can maintain and keep track of. |
18 | | -- A Behavior Tree flows executing each of its children, which return some kind of success or failure state. Only those branches following a successful node will be executed. A BTNode must return either success or failure, and can suspend execution only with a yield() call, after which it will remain in a running state until execution is completed. When a BTNode is in running state, the tree will progressively suspend execution (with the only exeption being BTParallel ) until all of the children complete execution. This is for optimisation purposes. |
19 | | -- The flow of the tree is defined by the so called composite nodes: BTSequence, BTSelector, BTRandomSelector, BTRandomSequence, BTParallel which all inherit from BTComposite. A sequence is successfull if all the children are successful, while it fails if one of the children fails. The selector is the logical opposite, it succeeds if one children succeeds, and fails if all the children fail. A parallel will run all the children and always succeed regardless, WITHOUT waiting for children to complete execution. The base composite node runs all the children and always succeeds, but it also waits for execution completion. |
20 | | -- The actions of your AI behavior are carried out in BTLeaf nodes. Add a BTLeaf, then do 'extend script'. Now you can define your own behavior in this script by overriding the _ _tick()_ method. Your actions will go here. Make sure to read the comments in the base script to know the best practices. Also remember BTLeaf shouldn't have children. |
21 | | -- BTDecorator is used to customise the execution of a child node. They can only have ONE child. |
22 | | -- BTConditional is the most common type of decorator. Add a BTConditional and extend the script, then override the _ _pre_tick()_ method to define the conditions under which the child will be executed. Make sure you read the comment cause there is a useful example there. |
23 | | -- BTGuards are decorators which can be used to temporarily lock branches. Optionally, you can assign an unlocker, which will override the lock time specified. There is also the option to assign a locker. BTGuards can make your behavior very rich and reactive, as well as optimised, as they avoid unnecessary branching and repetition. |
24 | | -- Other decorators allow you to loop execution, reverse the result of tick, and so on. There is a lot you can do by customising execution through decorators. |
25 | | -- Good practice is to use the provided nodes and follow the design pattern of the behavior tree. But since this is a purely code based implementation without any visual editor, you have a lot of control over the design and thus a margin of error. These are just useful scripts that follow some "good practices" but are not bound to them, if not for a couple of basic rules. It is up to you to decide how you design your behavior tree, but keep in mind that if you misuse it you will not benefit from the power of the behavior tree pattern. (for example, you could even use the base BTNode for everything and just extend it everytime, although it would be a mess) |
26 | | -- You could have a huge behaviour tree, but the best practice is to follow the component philosophy of Godot and make several smaller behaviour trees for each component of your scene. For example, a tree for your movement controller, a tree for your weapon controller, a tree for your pathfinder component, etc.. A behaviour tree can only have one blackboard, but the same blackboard can be used by many trees, so this is particularly handy if you wanna have several trees without also making multiple blackboards. Personally, the reason why I have the blackboard as a decoupled component, is because I wanted to make squads of enemies sharing the same data but behaving independently, so this is a use case for this. Moreover, I usually have several components in my actors, and I wanna use the same database for different tree. |
| 1 | +# GodotBT: Behavior Tree Framework for Godot 4.x |
| 2 | + |
| 3 | +A flexible, extensible behavior tree framework for Godot 4.x that makes it easy to create complex AI behaviors for your games. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +GodotBT provides a complete behavior tree implementation for the Godot Engine, allowing you to create sophisticated AI behaviors with a clear, modular structure. The framework follows behavior tree design principles with a focus on reusability and separation of concerns. |
| 8 | + |
| 9 | +## Key Features |
| 10 | + |
| 11 | +- **Complete Behavior Tree Implementation**: Core composite nodes, decorators, services, tasks, and conditions |
| 12 | +- **Reusable Behavior Trees**: Define a behavior tree once and use it across multiple agents with their own contexts |
| 13 | +- **Blackboard System**: Flexible data sharing between nodes with typed accessors and change detection |
| 14 | +- **Reactive Conditions**: Trigger behavior changes based on world events with configurable abort scopes |
| 15 | +- **Service System**: Run periodic background tasks with customizable frequency |
| 16 | +- **Context Separation**: Each agent maintains its own execution context with the shared tree |
| 17 | +- **Utility Components**: Helpers like BTTargetKey for simplified movement and targeting operations |
| 18 | +- **Example Implementation**: Includes a complete demo with enemies that can patrol, chase the player, and react to events |
| 19 | + |
| 20 | +## Core Components |
| 21 | + |
| 22 | +### Composite Nodes |
| 23 | + |
| 24 | +- **BTSelector**: Runs child nodes until one succeeds or all fail |
| 25 | +- **BTSequence**: Runs child nodes until one fails or all succeed |
| 26 | +- **BTParallel**: Runs all child nodes simultaneously |
| 27 | +- **BTRandomSelector/BTRandomSequence**: Random execution order versions of selector and sequence |
| 28 | + |
| 29 | +### Decorators |
| 30 | + |
| 31 | +- **BTInverter**: Inverts the result of a node |
| 32 | +- **BTRepeater**: Repeats a node a specified number of times |
| 33 | +- **BTRepeatUntil**: Repeats a node until it returns a specific result |
| 34 | +- **BTAlwaysReturn**: Forces a node to return a specific result |
| 35 | + |
| 36 | +### Conditions |
| 37 | + |
| 38 | +- **BTBlackboardBasedCondition**: Condition based on blackboard values |
| 39 | +- **BTReactiveCondition**: Condition that can trigger aborts |
| 40 | +- **BTCheckNonZeroBBEntry**: Checks if a blackboard value is non-zero/non-empty |
| 41 | +- **BTCompareBBEntries**: Compares two blackboard entries |
| 42 | + |
| 43 | +### Services |
| 44 | + |
| 45 | +- **BTService**: Base class for services that run periodically |
| 46 | +- Custom services in examples like **BTPlayerDetector**, **BTPatrolPathFollower** |
| 47 | + |
| 48 | +### Tasks |
| 49 | + |
| 50 | +- **BTTask**: Base class for leaf nodes that perform actions |
| 51 | +- **BTWait**: Wait for a specified amount of time |
| 52 | +- Example implementations for movement, path finding, and more |
| 53 | + |
| 54 | +## Installation |
| 55 | + |
| 56 | +1. Clone or download this repository |
| 57 | +2. Copy the `addons/godot_bt` folder into your project's `addons` folder |
| 58 | +3. Enable the plugin in Project Settings > Plugins |
| 59 | + |
| 60 | +## Basic Usage |
| 61 | + |
| 62 | +### Creating a Behavior Tree |
| 63 | + |
| 64 | +1. Create a new scene with a root node of type `BehaviorTree` |
| 65 | +2. Add a `BTSelector` or `BTSequence` as the first child |
| 66 | +3. Build your behavior tree by adding more composite nodes and tasks |
| 67 | +4. Save the scene |
| 68 | + |
| 69 | +### Using the Behavior Tree with Multiple Agents |
| 70 | + |
| 71 | +```gdscript |
| 72 | +# Level.gd - Sets up the behavior tree and passes it to agents |
| 73 | +extends Node2D |
| 74 | +
|
| 75 | +func _ready(): |
| 76 | + # Find all agents and set their behavior trees |
| 77 | + for enemy in get_tree().get_nodes_in_group("enemies"): |
| 78 | + enemy.run_behavior_tree() |
| 79 | +``` |
| 80 | + |
| 81 | +```gdscript |
| 82 | +# Enemy.gd - Each agent handles its own context |
| 83 | +extends CharacterBody2D |
| 84 | +
|
| 85 | +@export var bt: BehaviorTree |
| 86 | +@export var patrol_path: Node2D |
| 87 | +
|
| 88 | +var ctx: BTContext |
| 89 | +
|
| 90 | +# Called by the level or manager |
| 91 | +func run_behavior_tree() -> void: |
| 92 | + if not is_instance_valid(bt): |
| 93 | + return |
| 94 | +
|
| 95 | + ctx = bt.create_context(self, Blackboard.new()) |
| 96 | +
|
| 97 | + # Set up blackboard values for this agent |
| 98 | + if patrol_path: |
| 99 | + var patrol_points: Array = [] |
| 100 | + for patrol_pt in patrol_path.get_children(): |
| 101 | + patrol_points.append(patrol_pt.global_position) |
| 102 | + ctx.blackboard.set_value("patrol_points", patrol_points) |
| 103 | +
|
| 104 | +func _physics_process(delta: float) -> void: |
| 105 | + if is_instance_valid(bt) and ctx: |
| 106 | + bt.tick(ctx, delta) |
| 107 | +``` |
| 108 | + |
| 109 | +## Example Implementation |
| 110 | + |
| 111 | +The included example demonstrates: |
| 112 | + |
| 113 | +1. **Enemy Patrol System**: Enemies follow patrol paths or look in random directions |
| 114 | +2. **Player Detection**: A service that detects the player within a specified range |
| 115 | +3. **Chase Behavior**: Enemies chase the player when detected |
| 116 | +4. **Navigation**: Path finding to navigate around obstacles |
| 117 | + |
| 118 | +To see the example in action, open the `example/TestLevel.tscn` scene. |
| 119 | + |
| 120 | +## Extending the Framework |
| 121 | + |
| 122 | +The GodotBT framework is designed to be highly extensible. You can: |
| 123 | + |
| 124 | +### Create Custom Tasks |
| 125 | + |
| 126 | +```gdscript |
| 127 | +class_name MyCustomTask extends BTTask |
| 128 | +
|
| 129 | +@export var _some_parameter: float = 1.0 |
| 130 | +
|
| 131 | +func _tick(ctx: BTContext) -> BTResult: |
| 132 | + # Your implementation here |
| 133 | + if some_condition: |
| 134 | + return BTResult.SUCCESS |
| 135 | + else: |
| 136 | + return BTResult.RUNNING |
| 137 | +``` |
| 138 | + |
| 139 | +### Create Custom Conditions |
| 140 | + |
| 141 | +```gdscript |
| 142 | +class_name MyCustomCondition extends BTCondition |
| 143 | +
|
| 144 | +func _tick(ctx: BTContext) -> bool: |
| 145 | + # Your implementation here |
| 146 | + return some_condition_check |
| 147 | +``` |
| 148 | + |
| 149 | +### Create Custom Services |
| 150 | + |
| 151 | +```gdscript |
| 152 | +class_name MyCustomService extends BTService |
| 153 | +
|
| 154 | +func _tick(ctx: BTContext) -> void: |
| 155 | + # Your implementation here |
| 156 | + ctx.blackboard.set_value("some_key", calculate_some_value()) |
| 157 | +``` |
| 158 | + |
| 159 | +## License |
| 160 | + |
| 161 | +This project is available under the MIT License. |
| 162 | + |
| 163 | +## Contributing |
| 164 | + |
| 165 | +Contributions are welcome! Feel free to submit pull requests or open issues for bugs and feature requests. |
0 commit comments