├── .gitattributes ├── Behaviour Tree Friends.yyp ├── builded.md ├── example.md ├── example_running.gif ├── example_tree.jpg ├── nodes.md ├── objects ├── o_bt_tester │ ├── Create_0.gml │ └── Step_0.gml ├── o_enemy │ ├── Create_0.gml │ ├── Draw_0.gml │ ├── Step_0.gml │ └── o_enemy.yy └── o_mouse_follower │ ├── Create_0.gml │ ├── Draw_0.gml │ ├── Step_0.gml │ └── o_mouse_follower.yy ├── options ├── amazonfire │ └── options_amazonfire.yy ├── android │ └── options_android.yy ├── html5 │ └── options_html5.yy ├── ios │ └── options_ios.yy ├── linux │ └── options_linux.yy ├── mac │ └── options_mac.yy ├── main │ └── options_main.yy ├── tvos │ └── options_tvos.yy └── windows │ └── options_windows.yy ├── readme.md ├── readme_logo.png ├── rooms └── Room1 │ └── Room1.yy ├── scripts ├── BehaviourTree │ ├── BehaviourTree.gml │ └── BehaviourTree.yy ├── __BTConfig │ ├── __BTConfig.gml │ └── __BTConfig.yy └── behavior_chase │ ├── BT_test.yy │ ├── behavior_chase.gml │ └── behavior_chase.yy └── sprites ├── Sprite1 ├── Sprite1.yy ├── d47c3ffb-aa12-4455-8cb7-22cd1be52178.png └── layers │ └── d47c3ffb-aa12-4455-8cb7-22cd1be52178 │ └── 04284397-b0cd-4c59-8518-3ed983155443.png └── Sprite2 ├── 9c751507-4992-43c3-9dde-795606e8c68d.png ├── Sprite2.yy └── layers └── 9c751507-4992-43c3-9dde-795606e8c68d └── 4fdad78a-d4c5-4cdc-8b18-9a23df9ac50a.png /.gitattributes: -------------------------------------------------------------------------------- 1 | # Re-classify .yy files (for GMS 2 projects) 2 | *.yy linguist-language=GML 3 | -------------------------------------------------------------------------------- /Behaviour Tree Friends.yyp: -------------------------------------------------------------------------------- 1 | { 2 | "resources": [ 3 | {"id":{"name":"behavior_chase","path":"scripts/behavior_chase/behavior_chase.yy",},"order":3,}, 4 | {"id":{"name":"Sprite1","path":"sprites/Sprite1/Sprite1.yy",},"order":4,}, 5 | {"id":{"name":"o_enemy","path":"objects/o_enemy/o_enemy.yy",},"order":2,}, 6 | {"id":{"name":"Sprite2","path":"sprites/Sprite2/Sprite2.yy",},"order":5,}, 7 | {"id":{"name":"BehaviourTree","path":"scripts/BehaviourTree/BehaviourTree.yy",},"order":2,}, 8 | {"id":{"name":"o_mouse_follower","path":"objects/o_mouse_follower/o_mouse_follower.yy",},"order":1,}, 9 | {"id":{"name":"__BTConfig","path":"scripts/__BTConfig/__BTConfig.yy",},"order":0,}, 10 | {"id":{"name":"Room1","path":"rooms/Room1/Room1.yy",},"order":0,}, 11 | ], 12 | "Options": [ 13 | {"name":"Amazon Fire","path":"options/amazonfire/options_amazonfire.yy",}, 14 | {"name":"Android","path":"options/android/options_android.yy",}, 15 | {"name":"HTML5","path":"options/html5/options_html5.yy",}, 16 | {"name":"iOS","path":"options/ios/options_ios.yy",}, 17 | {"name":"Linux","path":"options/linux/options_linux.yy",}, 18 | {"name":"macOS","path":"options/mac/options_mac.yy",}, 19 | {"name":"Main","path":"options/main/options_main.yy",}, 20 | {"name":"tvOS","path":"options/tvos/options_tvos.yy",}, 21 | {"name":"Windows","path":"options/windows/options_windows.yy",}, 22 | ], 23 | "isDnDProject": false, 24 | "isEcma": false, 25 | "tutorialPath": "", 26 | "configs": { 27 | "name": "Default", 28 | "children": [], 29 | }, 30 | "RoomOrderNodes": [ 31 | {"roomId":{"name":"Room1","path":"rooms/Room1/Room1.yy",},}, 32 | ], 33 | "Folders": [ 34 | {"folderPath":"folders/GMLBehaviorTree.yy","order":11,"resourceVersion":"1.0","name":"GMLBehaviorTree","tags":[],"resourceType":"GMFolder",}, 35 | {"folderPath":"folders/example.yy","order":12,"resourceVersion":"1.0","name":"example","tags":[],"resourceType":"GMFolder",}, 36 | ], 37 | "AudioGroups": [ 38 | {"targets":-1,"resourceVersion":"1.3","name":"audiogroup_default","resourceType":"GMAudioGroup",}, 39 | ], 40 | "TextureGroups": [ 41 | {"isScaled":true,"autocrop":true,"border":2,"mipsToGenerate":0,"groupParent":null,"targets":-1,"resourceVersion":"1.3","name":"Default","resourceType":"GMTextureGroup",}, 42 | ], 43 | "IncludedFiles": [], 44 | "MetaData": { 45 | "IDEVersion": "2.3.3.570", 46 | }, 47 | "resourceVersion": "1.4", 48 | "name": "Behaviour Tree Friends", 49 | "tags": [], 50 | "resourceType": "GMProject", 51 | } -------------------------------------------------------------------------------- /builded.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | # GML Behavior Tree 8 | 9 | The classic Behavior Tree to GMS 2.3+ 10 | 11 | ## How its builded 12 | 13 | Our implementation is builded all above the same BTreeNode struct: 14 | 15 | ### Variables: 16 | 17 | | Name | Description | 18 | |------------------|------------------------------------| 19 | | name | The node name | 20 | | status | The Current Status of the node | 21 | | visited | If it already been visited or not | 22 | | children | The node children | 23 | | children_arr_len | The actual children array length | 24 | | black_board_ref | The reference to blackboard struct | 25 | 26 | ### Methods: 27 | 28 | | Name | Description | 29 | |------------------------|----------------------------------------------------------------------------| 30 | | Init() | Call this for some extra configs when visiting the node for the first time | 31 | | Process() | Called in every step of the game. Need to return one of the BTStates enum | 32 | | ChildAdd(BTreeNode) | Used to add a child to the node | 33 | | NodeProcess(BTreeNode) | Process other nodes | 34 | -------------------------------------------------------------------------------- /example.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | # GML Behavior Tree 8 | 9 | The classic Behavior Tree to GMS 2.3+ 10 | 11 | 12 | ## How to use 13 | 14 | You can see this example with the projects file. 15 | We choose no enter in game maker details like objects, etc. 16 | it's just the Behavior tree use. 17 | 18 | This example implements this tree: 19 | 20 | ![example tree](./example_tree.jpg) 21 | 22 | > before mount your behavior tree try figure out about it and make a diagram like that 23 | 24 | First of all we create our Leaf nodes inside a script file 25 | 26 | ``` gml 27 | behavior_chase.gml 28 | 29 | /// @param obj_ref 30 | /// @param range 31 | function TaskInstanceInRange(obj, range) : BTreeLeaf() constructor { 32 | name = "Task Instance In Range"; 33 | object_find = obj; 34 | range_limit = range; 35 | 36 | instance_ref = noone; 37 | 38 | /// @override 39 | static Init = function(){ 40 | instance_ref = instance_find(object_find, 0); 41 | } 42 | 43 | /// @override 44 | static Process = function(){ 45 | if(instance_exists(instance_ref) && point_distance(black_board_ref.user.x, black_board_ref.user.y, instance_ref.x, instance_ref.y) <= range_limit) 46 | return BTStates.Success; 47 | else 48 | return BTStates.Failure; 49 | } 50 | } 51 | ``` 52 | 53 | > remember: the process need to return a BTStates state 54 | 55 | See that in the Init method we start the behavior variables while in Process method we run the behavior. The tree general data stay in the blackboard. 56 | Notice that the behavior can receive some parameters to promote reuses 57 | 58 | After the TaskInstanceInRange is ready we create the other behaviors: 59 | 60 |
61 |
Click here to see some code 62 | 63 | ``` gml 64 | behavior_chase.gml 65 | 66 | ... 67 | /// @param speed 68 | /// @param timer_secs 69 | function TaskPatrolSimple(speed, timer_secs) : BTreeLeaf() constructor { 70 | name = "Taks Patrol Simple"; 71 | patrol_speed = speed; 72 | 73 | patrol_spd_x = 0; 74 | patrol_spd_y = 0; 75 | 76 | patrol_direction = 0; 77 | patrol_timer_max = timer_secs * room_speed; 78 | patrol_timer = 0; 79 | 80 | /// @override 81 | static Process = function(){ 82 | if(--patrol_timer <= 0){ 83 | patrol_direction = irandom(360); 84 | patrol_spd_x = lengthdir_x(patrol_speed, patrol_direction); 85 | patrol_spd_y = lengthdir_y(patrol_speed, patrol_direction); 86 | patrol_timer = patrol_timer_max; 87 | } 88 | 89 | black_board_ref.user.x += patrol_spd_x; 90 | black_board_ref.user.y += patrol_spd_y; 91 | return BTStates.Success; 92 | } 93 | } 94 | 95 | /// @param instance_chase 96 | /// @param speed_chase 97 | /// @param distance_max 98 | /// @param distance_min 99 | function TaskChaseInstance(instance_chase, speed_chase, distance_max, distance_min) : BTreeLeaf() constructor{ 100 | name = "Task Chase Instance"; 101 | 102 | chase_speed = speed_chase; 103 | instance_to_chase = instance_chase; 104 | distance_maximun_to_stop_chase = distance_max; 105 | distance_minimun_to_stop_chase = distance_min; 106 | 107 | ///@override 108 | static Process = function(){ 109 | if(instance_exists(instance_to_chase)){ 110 | 111 | // Check Stop chasing 112 | var _dist = point_distance(black_board_ref.user.x, black_board_ref.user.y, instance_to_chase.x, instance_to_chase.y); 113 | if(_dist <= distance_minimun_to_stop_chase) 114 | return BTStates.Success; 115 | else if (_dist >= distance_maximun_to_stop_chase) 116 | return BTStates.Failure; 117 | else { 118 | // Moving towards chasing 119 | var _dir = point_direction(black_board_ref.user.x, black_board_ref.user.y, instance_to_chase.x, instance_to_chase.y); 120 | black_board_ref.user.x += lengthdir_x(chase_speed, _dir); 121 | black_board_ref.user.y += lengthdir_y(chase_speed, _dir); 122 | 123 | return BTStates.Running; 124 | } 125 | } 126 | else 127 | return BTStates.Failure 128 | 129 | } 130 | 131 | } 132 | 133 | /// @param instance_target 134 | /// @param secs_between_hits 135 | function TaskMeleeHitTarget(instance_target, secs_preparation) : BTreeLeaf() constructor{ 136 | name = "Task Melee Hit on Target"; 137 | 138 | target_hit = instance_target; 139 | time_preparation_max = secs_preparation * room_speed; 140 | time_preparation = 0; 141 | 142 | /// @override 143 | static Process = function(){ 144 | if(!instance_exists(target_hit)) return BTStates.Failure; 145 | if(++time_preparation >= time_preparation_max){ 146 | time_preparation = 0; 147 | target_hit.life -= 10; 148 | return BTStates.Success; 149 | } 150 | else 151 | return BTStates.Running; 152 | } 153 | } 154 | ``` 155 |
156 |
157 | With our behaviors done we can finally make our tree based on the diagram. 158 | 159 | To mount the tree we first instantiate the nodes 160 | 161 | ``` gml 162 | o_enemy -> create 163 | 164 | /// @desc bt Start 165 | bt_root = new BTreeRoot(id); 166 | 167 | // --- 168 | var _selector_root = new BTreeSelector(); 169 | var _sequence_chase = new BTreeSequence(); 170 | var _chase_in_range = new TaskInstanceInRange(o_mouse_follower, 200); 171 | var _chase_behave = new TaskChaseInstance(o_mouse_follower, 2.5, 400, 64); 172 | var _succeder = new BTreeSucceeder(); 173 | var _hit = new TaskMeleeHitTarget(o_mouse_follower, 1.5); 174 | ``` 175 | 176 | Notice that the BTreeRoot node receives the object id as parameter. With this the blackboard.user will point directly to our instance. 177 | 178 | The other nodes receive some configurations like range and speed. 179 | 180 | With all our nodes created, we can mount our tree just like the diagram using the node.addChild() method: 181 | 182 | ``` gml 183 | o_enemy -> create 184 | 185 | ... 186 | bt_root.ChildAdd(_selector_root); 187 | 188 | _sequence_chase.ChildAdd(_chase_in_range); 189 | _sequence_chase.ChildAdd(_chase_behave); 190 | _sequence_chase.ChildAdd(_succeder); 191 | _succeder.ChildAdd(_hit); 192 | 193 | _selector_root.ChildAdd(_sequence_chase); 194 | _selector_root.ChildAdd(_patrol); 195 | ``` 196 | 197 | With our tree ready we just need to initialize it with 198 | 199 | ``` gml 200 | o_enemy -> create 201 | 202 | ... 203 | bt_root.Init(); 204 | ``` 205 | 206 | And to properly process the tree add this on the step event 207 | 208 | ``` gml 209 | o_enemy -> step 210 | 211 | bt_root.Process(); 212 | ``` 213 | 214 | And this is the final result 215 | 216 | ![example running](./example_running.gif) 217 | 218 | ## References 219 | 220 | - https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) 221 | - https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php 222 | -------------------------------------------------------------------------------- /example_running.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/example_running.gif -------------------------------------------------------------------------------- /example_tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/example_tree.jpg -------------------------------------------------------------------------------- /nodes.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | # GML Behavior Tree 8 | 9 | The classic Behavior Tree to GMS 2.3+ 10 | 11 | ## How our nodes works 12 | 13 | 14 | ### Composites 15 | 16 | A composite is a node that can have more than one child. They will process one or more of them children. 17 | 18 | | Name | Description | 19 | |------------------|------------------------------------| 20 | | Sequence | Process each child and when that return Success Process the next one| 21 | | Selector | Process each child, but only process the next if this actual returns Failure| 22 | 23 | 24 | ### Decorators 25 | 26 | A decorator is a node that can have only one child. They will process this child and transform the received status 27 | 28 | | Name | Description | 29 | |------------------|------------------------------------| 30 | | Succeeder | Process the child and always return Success| 31 | | Inverter | Process the child and invert the received Status| 32 | 33 | ### Leafs 34 | 35 | A leaf node is a node that will process the behavior. This need to return one of the BTStates enum. 36 | 37 | You can see details about how to create behaviors in [example.md](./example.md) 38 | 39 | ### Root 40 | 41 | The Root node is a custom node that will start our tree. Is responsible by startup the tree, init our Blackboard and some other configs. 42 | 43 | ## References 44 | 45 | - https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php 46 | -------------------------------------------------------------------------------- /objects/o_bt_tester/Create_0.gml: -------------------------------------------------------------------------------- 1 | b_tree = new BTreeRoot(id); 2 | 3 | b_tree.ChildAdd(find_and_chase_bt()); 4 | 5 | b_tree.Init(); -------------------------------------------------------------------------------- /objects/o_bt_tester/Step_0.gml: -------------------------------------------------------------------------------- 1 | 2 | b_tree.Process(); -------------------------------------------------------------------------------- /objects/o_enemy/Create_0.gml: -------------------------------------------------------------------------------- 1 | /// @desc bt Start 2 | bt_root = new BTreeRoot(id); 3 | 4 | // --- 5 | var _selector_root = new BTreeSelector(); 6 | var _sequence_chase = new BTreeSequence(); 7 | var _chase_in_range = new TaskInstanceInRange(o_mouse_follower, 200); 8 | var _chase_behave = new TaskChaseInstance(o_mouse_follower, 2.5, 400, 64); 9 | var _succeder = new BTreeSucceeder(); 10 | var _hit = new TaskMeleeHitTarget(o_mouse_follower, 1.5); 11 | var _patrol = new TaskPatrolSimple(1, 2); 12 | 13 | bt_root.ChildAdd(_selector_root); 14 | 15 | _sequence_chase.ChildAdd(_chase_in_range); 16 | _sequence_chase.ChildAdd(_chase_behave); 17 | _sequence_chase.ChildAdd(_succeder); 18 | _succeder.ChildAdd(_hit); 19 | 20 | _selector_root.ChildAdd(_sequence_chase); 21 | _selector_root.ChildAdd(_patrol); 22 | 23 | 24 | bt_root.Init(); 25 | -------------------------------------------------------------------------------- /objects/o_enemy/Draw_0.gml: -------------------------------------------------------------------------------- 1 | /// @description 2 | draw_self(); 3 | draw_circle(x, y, 200, true); -------------------------------------------------------------------------------- /objects/o_enemy/Step_0.gml: -------------------------------------------------------------------------------- 1 | /// @desc BT Process call 2 | bt_root.Process(); -------------------------------------------------------------------------------- /objects/o_enemy/o_enemy.yy: -------------------------------------------------------------------------------- 1 | { 2 | "spriteId": { 3 | "name": "Sprite1", 4 | "path": "sprites/Sprite1/Sprite1.yy", 5 | }, 6 | "solid": false, 7 | "visible": true, 8 | "spriteMaskId": null, 9 | "persistent": false, 10 | "parentObjectId": null, 11 | "physicsObject": false, 12 | "physicsSensor": false, 13 | "physicsShape": 1, 14 | "physicsGroup": 1, 15 | "physicsDensity": 0.5, 16 | "physicsRestitution": 0.1, 17 | "physicsLinearDamping": 0.1, 18 | "physicsAngularDamping": 0.1, 19 | "physicsFriction": 0.2, 20 | "physicsStartAwake": true, 21 | "physicsKinematic": false, 22 | "physicsShapePoints": [], 23 | "eventList": [ 24 | {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, 25 | {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, 26 | {"isDnD":false,"eventNum":0,"eventType":8,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, 27 | ], 28 | "properties": [], 29 | "overriddenProperties": [], 30 | "parent": { 31 | "name": "example", 32 | "path": "folders/example.yy", 33 | }, 34 | "resourceVersion": "1.0", 35 | "name": "o_enemy", 36 | "tags": [], 37 | "resourceType": "GMObject", 38 | } -------------------------------------------------------------------------------- /objects/o_mouse_follower/Create_0.gml: -------------------------------------------------------------------------------- 1 | /// @description 2 | life = 100; 3 | 4 | -------------------------------------------------------------------------------- /objects/o_mouse_follower/Draw_0.gml: -------------------------------------------------------------------------------- 1 | /// @description Health 2 | draw_self(); 3 | draw_healthbar( bbox_left, bbox_top - 32, 4 | bbox_right, bbox_top - 10, 5 | life, c_black, c_red, c_green, 6 | 0, true, true); 7 | -------------------------------------------------------------------------------- /objects/o_mouse_follower/Step_0.gml: -------------------------------------------------------------------------------- 1 | /// @desc Mouse follow With lerp 2 | x = lerp(x, mouse_x,0.05) 3 | y = lerp(y, mouse_y,0.05) -------------------------------------------------------------------------------- /objects/o_mouse_follower/o_mouse_follower.yy: -------------------------------------------------------------------------------- 1 | { 2 | "spriteId": { 3 | "name": "Sprite2", 4 | "path": "sprites/Sprite2/Sprite2.yy", 5 | }, 6 | "solid": false, 7 | "visible": true, 8 | "spriteMaskId": null, 9 | "persistent": false, 10 | "parentObjectId": null, 11 | "physicsObject": false, 12 | "physicsSensor": false, 13 | "physicsShape": 1, 14 | "physicsGroup": 1, 15 | "physicsDensity": 0.5, 16 | "physicsRestitution": 0.1, 17 | "physicsLinearDamping": 0.1, 18 | "physicsAngularDamping": 0.1, 19 | "physicsFriction": 0.2, 20 | "physicsStartAwake": true, 21 | "physicsKinematic": false, 22 | "physicsShapePoints": [], 23 | "eventList": [ 24 | {"isDnD":false,"eventNum":0,"eventType":3,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, 25 | {"isDnD":false,"eventNum":0,"eventType":0,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, 26 | {"isDnD":false,"eventNum":0,"eventType":8,"collisionObjectId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMEvent",}, 27 | ], 28 | "properties": [ 29 | {"varType":3,"value":"True","rangeEnabled":false,"rangeMin":0.0,"rangeMax":10.0,"listItems":[],"multiselect":false,"filters":[],"resourceVersion":"1.0","name":"follow","tags":[],"resourceType":"GMObjectProperty",}, 30 | ], 31 | "overriddenProperties": [], 32 | "parent": { 33 | "name": "example", 34 | "path": "folders/example.yy", 35 | }, 36 | "resourceVersion": "1.0", 37 | "name": "o_mouse_follower", 38 | "tags": [], 39 | "resourceType": "GMObject", 40 | } -------------------------------------------------------------------------------- /options/amazonfire/options_amazonfire.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_amazonfire_sync_android": false, 3 | "option_amazonfire_display_name": "Created with GameMaker Studio 2", 4 | "option_amazonfire_version": "1.0.0.0", 5 | "option_amazonfire_tools_from_version": false, 6 | "option_amazonfire_build_tools": "", 7 | "option_amazonfire_support_lib": "", 8 | "option_amazonfire_target_sdk": "", 9 | "option_amazonfire_minimum_sdk": "", 10 | "option_amazonfire_compile_sdk": "", 11 | "option_amazonfire_package_domain": "com", 12 | "option_amazonfire_package_company": "company", 13 | "option_amazonfire_package_product": "game", 14 | "option_amazonfire_orient_portrait": true, 15 | "option_amazonfire_orient_portrait_flipped": true, 16 | "option_amazonfire_orient_landscape": true, 17 | "option_amazonfire_orient_landscape_flipped": true, 18 | "option_amazonfire_gamepad_support": true, 19 | "option_amazonfire_lint": false, 20 | "option_amazonfire_install_location": 0, 21 | "option_amazonfire_sleep_margin": 4, 22 | "option_amazonfire_splash_screens_landscape": "${base_options_dir}/amazonfire/splash/landscape.png", 23 | "option_amazonfire_splash_screens_portrait": "${base_options_dir}/amazonfire/splash/portrait.png", 24 | "option_amazonfire_splash_time": 0, 25 | "option_amazonfire_launchscreen_fill": 0, 26 | "option_amazonfire_splashscreen_background_colour": 255, 27 | "option_amazonfire_tv_banner": "${base_options_dir}/amazonfire/tv_banner.png", 28 | "option_amazonfire_interpolate_pixels": false, 29 | "option_amazonfire_screen_depth": 0, 30 | "option_amazonfire_scale": 0, 31 | "option_amazonfire_texture_page": "2048x2048", 32 | "option_amazonfire_icon_ldpi": "${base_options_dir}/android/icons/ldpi.png", 33 | "option_amazonfire_icon_mdpi": "${base_options_dir}/android/icons/mdpi.png", 34 | "option_amazonfire_icon_hdpi": "${base_options_dir}/android/icons/hdpi.png", 35 | "option_amazonfire_icon_xhdpi": "${base_options_dir}/android/icons/xhdpi.png", 36 | "option_amazonfire_icon_xxhdpi": "${base_options_dir}/android/icons/xxhdpi.png", 37 | "option_amazonfire_icon_xxxhdpi": "${base_options_dir}/android/icons/xxxhdpi.png", 38 | "option_amazonfire_permission_write_external_storage": false, 39 | "option_amazonfire_permission_read_phone_state": false, 40 | "option_amazonfire_permission_network_state": false, 41 | "option_amazonfire_permission_internet": true, 42 | "option_amazonfire_permission_bluetooth": true, 43 | "option_amazonfire_permission_record_audio": false, 44 | "option_amazonfire_application_tag_inject": "", 45 | "resourceVersion": "1.0", 46 | "name": "Amazon Fire", 47 | "tags": [], 48 | "resourceType": "GMAmazonFireOptions", 49 | } -------------------------------------------------------------------------------- /options/android/options_android.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_android_sync_amazon": false, 3 | "option_android_display_name": "Created with GameMaker Studio 2", 4 | "option_android_version": "1.0.0.0", 5 | "option_android_tools_from_version": false, 6 | "option_android_build_tools": "", 7 | "option_android_support_lib": "", 8 | "option_android_target_sdk": "", 9 | "option_android_minimum_sdk": "", 10 | "option_android_compile_sdk": "", 11 | "option_android_package_domain": "com", 12 | "option_android_package_company": "company", 13 | "option_android_package_product": "game", 14 | "option_android_arch_armv7": true, 15 | "option_android_arch_x86": false, 16 | "option_android_arch_arm64": false, 17 | "option_android_arch_x86_64": false, 18 | "option_android_orient_portrait": true, 19 | "option_android_orient_portrait_flipped": true, 20 | "option_android_orient_landscape": true, 21 | "option_android_orient_landscape_flipped": true, 22 | "option_android_gamepad_support": true, 23 | "option_android_lint": false, 24 | "option_android_install_location": 0, 25 | "option_android_sleep_margin": 4, 26 | "option_android_splash_screens_landscape": "${base_options_dir}/android/splash/landscape.png", 27 | "option_android_splash_screens_portrait": "${base_options_dir}/android/splash/portrait.png", 28 | "option_android_splash_time": 0, 29 | "option_android_launchscreen_fill": 0, 30 | "option_android_splashscreen_background_colour": 255, 31 | "option_android_tv_banner": "${base_options_dir}/android/tv_banner.png", 32 | "option_android_interpolate_pixels": false, 33 | "option_android_screen_depth": 0, 34 | "option_android_device_support": 0, 35 | "option_android_scale": 0, 36 | "option_android_texture_page": "2048x2048", 37 | "option_android_icon_ldpi": "${base_options_dir}/android/icons/ldpi.png", 38 | "option_android_icon_mdpi": "${base_options_dir}/android/icons/mdpi.png", 39 | "option_android_icon_hdpi": "${base_options_dir}/android/icons/hdpi.png", 40 | "option_android_icon_xhdpi": "${base_options_dir}/android/icons/xhdpi.png", 41 | "option_android_icon_xxhdpi": "${base_options_dir}/android/icons/xxhdpi.png", 42 | "option_android_icon_xxxhdpi": "${base_options_dir}/android/icons/xxxhdpi.png", 43 | "option_android_icon_adaptive_generate": false, 44 | "option_android_icon_adaptive_ldpi": "${base_options_dir}/android/icons_adaptive/ldpi.png", 45 | "option_android_icon_adaptive_mdpi": "${base_options_dir}/android/icons_adaptive/mdpi.png", 46 | "option_android_icon_adaptive_hdpi": "${base_options_dir}/android/icons_adaptive/hdpi.png", 47 | "option_android_icon_adaptive_xhdpi": "${base_options_dir}/android/icons_adaptive/xhdpi.png", 48 | "option_android_icon_adaptive_xxhdpi": "${base_options_dir}/android/icons_adaptive/xxhdpi.png", 49 | "option_android_icon_adaptive_xxxhdpi": "${base_options_dir}/android/icons_adaptive/xxxhdpi.png", 50 | "option_android_icon_adaptivebg_ldpi": "${base_options_dir}/android/icons_adaptivebg/ldpi.png", 51 | "option_android_icon_adaptivebg_mdpi": "${base_options_dir}/android/icons_adaptivebg/mdpi.png", 52 | "option_android_icon_adaptivebg_hdpi": "${base_options_dir}/android/icons_adaptivebg/hdpi.png", 53 | "option_android_icon_adaptivebg_xhdpi": "${base_options_dir}/android/icons_adaptivebg/xhdpi.png", 54 | "option_android_icon_adaptivebg_xxhdpi": "${base_options_dir}/android/icons_adaptivebg/xxhdpi.png", 55 | "option_android_icon_adaptivebg_xxxhdpi": "${base_options_dir}/android/icons_adaptivebg/xxxhdpi.png", 56 | "option_android_use_facebook": false, 57 | "option_android_facebook_id": "", 58 | "option_android_facebook_app_display_name": "", 59 | "option_android_google_cloud_saving": false, 60 | "option_android_google_services_app_id": "", 61 | "option_android_permission_write_external_storage": false, 62 | "option_android_permission_read_phone_state": false, 63 | "option_android_permission_network_state": false, 64 | "option_android_permission_internet": true, 65 | "option_android_permission_bluetooth": true, 66 | "option_android_permission_record_audio": false, 67 | "option_android_application_tag_inject": "", 68 | "option_android_google_apk_expansion": false, 69 | "option_android_google_dynamic_asset_delivery": false, 70 | "option_android_google_licensing_public_key": "", 71 | "option_android_tv_isgame": true, 72 | "resourceVersion": "1.0", 73 | "name": "Android", 74 | "tags": [], 75 | "resourceType": "GMAndroidOptions", 76 | } -------------------------------------------------------------------------------- /options/html5/options_html5.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_html5_browser_title": "Created with GameMaker Studio 2", 3 | "option_html5_version": "1.0.0.0", 4 | "option_html5_foldername": "html5game", 5 | "option_html5_outputname": "index.html", 6 | "option_html5_splash_png": "${base_options_dir}/html5/splash.png", 7 | "option_html5_usesplash": false, 8 | "option_html5_outputdebugtoconsole": true, 9 | "option_html5_display_cursor": true, 10 | "option_html5_localrunalert": true, 11 | "option_html5_index": "", 12 | "option_html5_loadingbar": "", 13 | "option_html5_jsprepend": "", 14 | "option_html5_icon": "${base_options_dir}/html5/fav.ico", 15 | "option_html5_allow_fullscreen": true, 16 | "option_html5_interpolate_pixels": true, 17 | "option_html5_centregame": false, 18 | "option_html5_usebuiltinparticles": true, 19 | "option_html5_usebuiltinfont": true, 20 | "option_html5_webgl": 2, 21 | "option_html5_scale": 0, 22 | "option_html5_texture_page": "2048x2048", 23 | "option_html5_use_facebook": false, 24 | "option_html5_facebook_id": "", 25 | "option_html5_facebook_app_display_name": "", 26 | "option_html5_flurry_enable": false, 27 | "option_html5_flurry_id": "", 28 | "option_html5_google_analytics_enable": false, 29 | "option_html5_google_tracking_id": "", 30 | "resourceVersion": "1.0", 31 | "name": "HTML5", 32 | "tags": [], 33 | "resourceType": "GMHtml5Options", 34 | } -------------------------------------------------------------------------------- /options/ios/options_ios.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_ios_display_name": "Created with GameMaker Studio 2", 3 | "option_ios_bundle_name": "com.company.game", 4 | "option_ios_version": "1.0.0.0", 5 | "option_ios_output_dir": "~/gamemakerstudio2", 6 | "option_ios_team_id": "", 7 | "option_ios_orientation_portrait": true, 8 | "option_ios_orientation_portrait_flipped": true, 9 | "option_ios_orientation_landscape": true, 10 | "option_ios_orientation_landscape_flipped": true, 11 | "option_ios_devices": 2, 12 | "option_ios_defer_home_indicator": false, 13 | "option_ios_icon_iphone_app_120": "${base_options_dir}/ios/icons/app/iphone_120.png", 14 | "option_ios_icon_iphone_app_180": "${base_options_dir}/ios/icons/app/iphone_180.png", 15 | "option_ios_icon_ipad_app_76": "${base_options_dir}/ios/icons/app/ipad_76.png", 16 | "option_ios_icon_ipad_app_152": "${base_options_dir}/ios/icons/app/ipad_152.png", 17 | "option_ios_icon_ipad_pro_app_167": "${base_options_dir}/ios/icons/app/ipad_pro_167.png", 18 | "option_ios_icon_iphone_notification_40": "${base_options_dir}/ios/icons/notification/iphone_40.png", 19 | "option_ios_icon_iphone_notification_60": "${base_options_dir}/ios/icons/notification/iphone_60.png", 20 | "option_ios_icon_ipad_notification_20": "${base_options_dir}/ios/icons/notification/ipad_20.png", 21 | "option_ios_icon_ipad_notification_40": "${base_options_dir}/ios/icons/notification/ipad_40.png", 22 | "option_ios_icon_iphone_spotlight_80": "${base_options_dir}/ios/icons/spotlight/iphone_80.png", 23 | "option_ios_icon_iphone_spotlight_120": "${base_options_dir}/ios/icons/spotlight/iphone_120.png", 24 | "option_ios_icon_ipad_spotlight_40": "${base_options_dir}/ios/icons/spotlight/ipad_40.png", 25 | "option_ios_icon_ipad_spotlight_80": "${base_options_dir}/ios/icons/spotlight/ipad_80.png", 26 | "option_ios_icon_iphone_settings_58": "${base_options_dir}/ios/icons/settings/iphone_58.png", 27 | "option_ios_icon_iphone_settings_87": "${base_options_dir}/ios/icons/settings/iphone_87.png", 28 | "option_ios_icon_ipad_settings_29": "${base_options_dir}/ios/icons/settings/ipad_29.png", 29 | "option_ios_icon_ipad_settings_58": "${base_options_dir}/ios/icons/settings/ipad_58.png", 30 | "option_ios_icon_itunes_artwork_1024": "${base_options_dir}/ios/icons/itunes/itunes_1024.png", 31 | "option_ios_splashscreen_background_colour": 255, 32 | "option_ios_launchscreen_image": "${base_options_dir}/ios/splash/launchscreen.png", 33 | "option_ios_launchscreen_image_landscape": "${base_options_dir}/ios/splash/launchscreen-landscape.png", 34 | "option_ios_launchscreen_fill": 0, 35 | "option_ios_interpolate_pixels": false, 36 | "option_ios_half_ipad1_textures": false, 37 | "option_ios_scale": 0, 38 | "option_ios_texture_page": "2048x2048", 39 | "option_ios_use_facebook": false, 40 | "option_ios_facebook_id": "", 41 | "option_ios_facebook_app_display_name": "", 42 | "option_ios_push_notifications": false, 43 | "option_ios_apple_sign_in": false, 44 | "option_ios_podfile_path": "${options_dir}/ios/Podfile", 45 | "option_ios_podfile_lock_path": "${options_dir}/ios/Podfile.lock", 46 | "resourceVersion": "1.3", 47 | "name": "iOS", 48 | "tags": [], 49 | "resourceType": "GMiOSOptions", 50 | } -------------------------------------------------------------------------------- /options/linux/options_linux.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_linux_display_name": "Created with GameMaker Studio 2", 3 | "option_linux_version": "1.0.0.0", 4 | "option_linux_maintainer_email": "", 5 | "option_linux_homepage": "http://www.yoyogames.com", 6 | "option_linux_short_desc": "", 7 | "option_linux_long_desc": "", 8 | "option_linux_splash_screen": "${base_options_dir}/linux/splash/splash.png", 9 | "option_linux_display_splash": false, 10 | "option_linux_icon": "${base_options_dir}/linux/icons/64.png", 11 | "option_linux_start_fullscreen": false, 12 | "option_linux_allow_fullscreen": false, 13 | "option_linux_interpolate_pixels": true, 14 | "option_linux_display_cursor": true, 15 | "option_linux_sync": false, 16 | "option_linux_resize_window": false, 17 | "option_linux_scale": 0, 18 | "option_linux_texture_page": "2048x2048", 19 | "option_linux_enable_steam": false, 20 | "option_linux_disable_sandbox": false, 21 | "resourceVersion": "1.0", 22 | "name": "Linux", 23 | "tags": [], 24 | "resourceType": "GMLinuxOptions", 25 | } -------------------------------------------------------------------------------- /options/mac/options_mac.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_mac_display_name": "Created with GameMaker Studio 2", 3 | "option_mac_app_id": "com.company.game", 4 | "option_mac_version": "1.0.0.0", 5 | "option_mac_output_dir": "~/gamemakerstudio2", 6 | "option_mac_team_id": "", 7 | "option_mac_signing_identity": "Developer ID Application:", 8 | "option_mac_copyright": "", 9 | "option_mac_splash_png": "${base_options_dir}/mac/splash/splash.png", 10 | "option_mac_icon_png": "${base_options_dir}/mac/icons/1024.png", 11 | "option_mac_installer_background_png": "${base_options_dir}/mac/splash/installer_background.png", 12 | "option_mac_menu_dock": false, 13 | "option_mac_display_cursor": true, 14 | "option_mac_start_fullscreen": false, 15 | "option_mac_allow_fullscreen": false, 16 | "option_mac_interpolate_pixels": true, 17 | "option_mac_vsync": false, 18 | "option_mac_resize_window": false, 19 | "option_mac_enable_retina": false, 20 | "option_mac_scale": 0, 21 | "option_mac_texture_page": "2048x2048", 22 | "option_mac_build_app_store": false, 23 | "option_mac_allow_incoming_network": false, 24 | "option_mac_allow_outgoing_network": false, 25 | "option_mac_app_category": "Games", 26 | "option_mac_enable_steam": false, 27 | "option_mac_disable_sandbox": false, 28 | "option_mac_apple_sign_in": false, 29 | "resourceVersion": "1.0", 30 | "name": "macOS", 31 | "tags": [], 32 | "resourceType": "GMMacOptions", 33 | } -------------------------------------------------------------------------------- /options/main/options_main.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_gameguid": "ef4643ad-26d1-4c0a-ba5d-03c7e9c77b8b", 3 | "option_gameid": "0", 4 | "option_game_speed": 60, 5 | "option_mips_for_3d_textures": false, 6 | "option_draw_colour": 4294967295, 7 | "option_window_colour": 255, 8 | "option_steam_app_id": "0", 9 | "option_sci_usesci": false, 10 | "option_author": "", 11 | "option_lastchanged": "", 12 | "option_spine_licence": false, 13 | "resourceVersion": "1.2", 14 | "name": "Main", 15 | "tags": [], 16 | "resourceType": "GMMainOptions", 17 | } -------------------------------------------------------------------------------- /options/tvos/options_tvos.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_tvos_display_name": "Made in GameMaker Studio 2", 3 | "option_tvos_bundle_name": "com.company.game", 4 | "option_tvos_version": "1.0.0.0", 5 | "option_tvos_output_dir": "~/GameMakerStudio2/tvOS", 6 | "option_tvos_team_id": "", 7 | "option_tvos_icon_400": "${base_options_dir}/tvos/icons/400.png", 8 | "option_tvos_icon_400_2x": "${base_options_dir}/tvos/icons/400_2x.png", 9 | "option_tvos_icon_1280": "${base_options_dir}/tvos/icons/1280.png", 10 | "option_tvos_topshelf": "${base_options_dir}/tvos/topshelf/topshelf.png", 11 | "option_tvos_topshelf_2x": "${base_options_dir}/tvos/topshelf/topshelf_2x.png", 12 | "option_tvos_topshelf_wide": "${base_options_dir}/tvos/topshelf/topshelf_wide.png", 13 | "option_tvos_topshelf_wide_2x": "${base_options_dir}/tvos/topshelf/topshelf_wide_2x.png", 14 | "option_tvos_splashscreen": "${base_options_dir}/tvos/splash/splash.png", 15 | "option_tvos_splashscreen_2x": "${base_options_dir}/tvos/splash/splash_2x.png", 16 | "option_tvos_splash_time": 0, 17 | "option_tvos_interpolate_pixels": true, 18 | "option_tvos_scale": 0, 19 | "option_tvos_texture_page": "2048x2048", 20 | "option_tvos_display_cursor": false, 21 | "option_tvos_push_notifications": false, 22 | "option_tvos_apple_sign_in": false, 23 | "option_tvos_podfile_path": "${options_dir}\\tvos\\Podfile", 24 | "option_tvos_podfile_lock_path": "${options_dir}\\tvos\\Podfile.lock", 25 | "resourceVersion": "1.3", 26 | "name": "tvOS", 27 | "tags": [], 28 | "resourceType": "GMtvOSOptions", 29 | } -------------------------------------------------------------------------------- /options/windows/options_windows.yy: -------------------------------------------------------------------------------- 1 | { 2 | "option_windows_display_name": "Created with GameMaker Studio 2", 3 | "option_windows_executable_name": "${project_name}.exe", 4 | "option_windows_version": "1.0.0.0", 5 | "option_windows_company_info": "YoYo Games Ltd", 6 | "option_windows_product_info": "Created with GameMaker Studio 2", 7 | "option_windows_copyright_info": "", 8 | "option_windows_description_info": "A GameMaker Studio 2 Game", 9 | "option_windows_display_cursor": true, 10 | "option_windows_icon": "${base_options_dir}/windows/icons/icon.ico", 11 | "option_windows_save_location": 0, 12 | "option_windows_splash_screen": "${base_options_dir}/windows/splash/splash.png", 13 | "option_windows_use_splash": false, 14 | "option_windows_start_fullscreen": false, 15 | "option_windows_allow_fullscreen_switching": false, 16 | "option_windows_interpolate_pixels": false, 17 | "option_windows_vsync": false, 18 | "option_windows_resize_window": false, 19 | "option_windows_borderless": false, 20 | "option_windows_scale": 0, 21 | "option_windows_copy_exe_to_dest": false, 22 | "option_windows_sleep_margin": 10, 23 | "option_windows_texture_page": "2048x2048", 24 | "option_windows_installer_finished": "${base_options_dir}/windows/installer/finished.bmp", 25 | "option_windows_installer_header": "${base_options_dir}/windows/installer/header.bmp", 26 | "option_windows_license": "${base_options_dir}/windows/installer/license.txt", 27 | "option_windows_nsis_file": "${base_options_dir}/windows/installer/nsis_script.nsi", 28 | "option_windows_enable_steam": false, 29 | "option_windows_disable_sandbox": false, 30 | "option_windows_steam_use_alternative_launcher": false, 31 | "option_windows_use_x64": false, 32 | "resourceVersion": "1.1", 33 | "name": "Windows", 34 | "tags": [], 35 | "resourceType": "GMWindowsOptions", 36 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | # GML Behavior Tree 8 | 9 | The classic Behavior Tree to GMS 2.3+ 10 | 11 | > if you don't know what you're doing here or need to learn what is a Behavior Tree, you can see it on our [references](#references) 12 | 13 | ## How to use 14 | ``` gml 15 | //create 16 | function TaskChangeColor() : BTreeLeaf() constructor{ 17 | name = "TaskChangeColor"; 18 | 19 | /// @override 20 | static Process = function(){ 21 | black_board_ref.user.image_blend = c_yellow 22 | return BTStates.Success; 23 | } 24 | } 25 | 26 | bt_root = new BTreeRoot(id); 27 | var change_color = new TaskChangeColor() 28 | bt_root.ChildAdd(change_color) 29 | 30 | bt_root.Init(); 31 | 32 | //step 33 | bt_root.Process(); 34 | ``` 35 | 36 | ## More details on 37 | 38 | - [Usage example](./example.md) 39 | - [Nodes docs](./nodes.md) 40 | - [How its builded](./builded.md) 41 | 42 | ## Contributors 43 | 44 | 45 | 46 | 47 | 48 | ## References 49 | 50 | - https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) 51 | - https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php 52 | 53 | And a especial thank you to [squircledev](https://github.com/squircledev) who shared some drafts with us :) 54 | -------------------------------------------------------------------------------- /readme_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/readme_logo.png -------------------------------------------------------------------------------- /rooms/Room1/Room1.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnd": false, 3 | "volume": 1.0, 4 | "parentRoom": null, 5 | "views": [ 6 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 7 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 8 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 9 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 10 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 11 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 12 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 13 | {"inherit":false,"visible":false,"xview":0,"yview":0,"wview":1366,"hview":768,"xport":0,"yport":0,"wport":1366,"hport":768,"hborder":32,"vborder":32,"hspeed":-1,"vspeed":-1,"objectId":null,}, 14 | ], 15 | "layers": [ 16 | {"instances":[ 17 | {"properties":[],"isDnd":false,"objectId":{"name":"o_mouse_follower","path":"objects/o_mouse_follower/o_mouse_follower.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":160.0,"y":384.0,"resourceVersion":"1.0","name":"inst_21BFD710","tags":[],"resourceType":"GMRInstance",}, 18 | {"properties":[],"isDnd":false,"objectId":{"name":"o_enemy","path":"objects/o_enemy/o_enemy.yy",},"inheritCode":false,"hasCreationCode":false,"colour":4294967295,"rotation":0.0,"scaleX":1.0,"scaleY":1.0,"imageIndex":0,"imageSpeed":1.0,"inheritedItemId":null,"frozen":false,"ignore":false,"inheritItemSettings":false,"x":1120.0,"y":384.0,"resourceVersion":"1.0","name":"inst_710534F9","tags":[],"resourceType":"GMRInstance",}, 19 | ],"visible":true,"depth":0,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Instances","tags":[],"resourceType":"GMRInstanceLayer",}, 20 | {"spriteId":null,"colour":4278190080,"x":0,"y":0,"htiled":false,"vtiled":false,"hspeed":0.0,"vspeed":0.0,"stretch":false,"animationFPS":15.0,"animationSpeedType":0,"userdefinedAnimFPS":false,"visible":true,"depth":100,"userdefinedDepth":false,"inheritLayerDepth":false,"inheritLayerSettings":false,"gridX":32,"gridY":32,"layers":[],"hierarchyFrozen":false,"resourceVersion":"1.0","name":"Background","tags":[],"resourceType":"GMRBackgroundLayer",}, 21 | ], 22 | "inheritLayers": false, 23 | "creationCodeFile": "", 24 | "inheritCode": false, 25 | "instanceCreationOrder": [ 26 | {"name":"inst_21BFD710","path":"rooms/Room1/Room1.yy",}, 27 | {"name":"inst_710534F9","path":"rooms/Room1/Room1.yy",}, 28 | ], 29 | "inheritCreationOrder": false, 30 | "sequenceId": null, 31 | "roomSettings": { 32 | "inheritRoomSettings": false, 33 | "Width": 1366, 34 | "Height": 768, 35 | "persistent": false, 36 | }, 37 | "viewSettings": { 38 | "inheritViewSettings": false, 39 | "enableViews": false, 40 | "clearViewBackground": false, 41 | "clearDisplayBuffer": true, 42 | }, 43 | "physicsSettings": { 44 | "inheritPhysicsSettings": false, 45 | "PhysicsWorld": false, 46 | "PhysicsWorldGravityX": 0.0, 47 | "PhysicsWorldGravityY": 10.0, 48 | "PhysicsWorldPixToMetres": 0.1, 49 | }, 50 | "parent": { 51 | "name": "example", 52 | "path": "folders/example.yy", 53 | }, 54 | "resourceVersion": "1.0", 55 | "name": "Room1", 56 | "tags": [], 57 | "resourceType": "GMRoom", 58 | } -------------------------------------------------------------------------------- /scripts/BehaviourTree/BehaviourTree.gml: -------------------------------------------------------------------------------- 1 | /* 2 | The classic Behavior Tree to GMS 2.3+ 3 | if you don't know what you're doing here or need to learn what is a Behavior Tree, 4 | you can see it on our references 5 | 6 | https://github.com/VitorEstevam/GML-Behaviour-Tree 7 | Mantained by @vitorstvm and @jalesjefferson 8 | */ 9 | 10 | enum BTStates 11 | { 12 | Running, 13 | Success, 14 | Failure, 15 | Off, 16 | } 17 | 18 | ///@abstract 19 | function BTreeNode() constructor{ 20 | name = "BT_TREE_NODE_BASE"; 21 | status = BTStates.Running; 22 | visited = false; 23 | 24 | children = []; 25 | children_arr_len = 0; 26 | black_board_ref = noone; 27 | 28 | static Init = function(){} 29 | 30 | static Process = function(){ 31 | return BTStates.Success; 32 | } 33 | 34 | static ChildAdd = function(_child){ 35 | array_push(children, _child); 36 | ++children_arr_len; 37 | } 38 | 39 | static NodeProcess = function(_node){ 40 | 41 | if(_node.visited == false){ // Initial configure 42 | _node.black_board_ref = black_board_ref; 43 | _node.visited = true; 44 | _node.Init(); 45 | } 46 | 47 | var _status = _node.Process(); // Returning State 48 | 49 | if(_status == BTStates.Running and black_board_ref.running_node == noone){ 50 | black_board_ref.running_node = _node 51 | } 52 | else if( _status != BTStates.Running and black_board_ref.running_node != noone){ 53 | black_board_ref.running_node = noone; 54 | } 55 | 56 | return _status 57 | } 58 | 59 | } 60 | 61 | ///@abstract 62 | function BTreeComposite() : BTreeNode() constructor{} 63 | 64 | ///@abstract 65 | function BTreeLeaf() : BTreeNode() constructor{} 66 | 67 | ///@abstract 68 | function BTreeDecorator() : BTreeNode() constructor{ 69 | /// @overwrite 70 | static ChildAdd = function(child_node){ 71 | children[0] = child_node; 72 | children_arr_len = 1; 73 | } 74 | } 75 | 76 | /// @param inst_id - Expects an instance id. 77 | function BTreeRoot(inst_id): BTreeNode() constructor{ 78 | name = "BT_ROOT"; 79 | status = BTStates.Off; 80 | array_push(children, noone); 81 | 82 | black_board = { 83 | user : inst_id, 84 | root_reference : other, 85 | running_node: noone, 86 | }; 87 | 88 | black_board_ref = black_board; 89 | 90 | /// @override 91 | static Init = function(){ 92 | status = BTStates.Running; 93 | } 94 | 95 | /// @override 96 | static Process = function(){ 97 | if(black_board.running_node != noone) 98 | NodeProcess(black_board.running_node); 99 | 100 | else if(children[0] != noone){ 101 | if(status == BTStates.Running) 102 | NodeProcess(children[0]); 103 | } 104 | } 105 | 106 | /// @override 107 | /// @param child_node - Expects a BTreeNode. 108 | static ChildAdd = function(child_node){ 109 | children[0] = child_node; 110 | children_arr_len = 1; 111 | } 112 | } 113 | 114 | function BTreeSequence() : BTreeComposite() constructor{ 115 | name = "BT_SEQUENCE"; 116 | 117 | /// @override 118 | static Process = function(){ 119 | var _i = 0; 120 | repeat(children_arr_len){ 121 | if(children[_i].status == BTStates.Running){ 122 | switch( NodeProcess(children[_i])){ 123 | case BTStates.Running: return BTStates.Running; 124 | case BTStates.Failure: return BTStates.Failure; 125 | } 126 | } 127 | 128 | ++_i; 129 | } 130 | 131 | return BTStates.Success; 132 | } 133 | } 134 | 135 | function BTreeSelector() : BTreeComposite() constructor{ 136 | name = "BT_SELECTOR"; 137 | 138 | /// @override 139 | static Process = function(){ 140 | var _i = 0; 141 | repeat(children_arr_len){ 142 | if(children[_i].status == BTStates.Running){ 143 | switch(NodeProcess(children[_i])){ 144 | case BTStates.Running: return BTStates.Running; 145 | case BTStates.Success: return BTStates.Success; 146 | } 147 | } 148 | 149 | ++_i; 150 | } 151 | 152 | return BTStates.Failure; 153 | } 154 | } 155 | 156 | function BTreeInverter() : BTreeDecorator() constructor{ 157 | name = "BT_Inverter"; 158 | 159 | /// @override 160 | static Process = function(){ 161 | var _state = NodeProcess(children[0]); 162 | switch(_state){ 163 | case BTStates.Failure: return BTStates.Success; 164 | case BTStates.Success: return BTStates.Failure; 165 | default: return _state; 166 | } 167 | } 168 | } 169 | 170 | function BTreeSucceeder() : BTreeDecorator() constructor{ 171 | name = "BT_Succeeder"; 172 | 173 | /// @override 174 | static Process = function(){ 175 | var _state = NodeProcess(children[0]); 176 | return BTStates.Success; 177 | } 178 | } 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /scripts/BehaviourTree/BehaviourTree.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "GMLBehaviorTree", 6 | "path": "folders/GMLBehaviorTree.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "BehaviourTree", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /scripts/__BTConfig/__BTConfig.gml: -------------------------------------------------------------------------------- 1 | #macro BTree_version "1.0.0" 2 | 3 | show_debug_message("GMLBehaviorTree version "+BTree_version) -------------------------------------------------------------------------------- /scripts/__BTConfig/__BTConfig.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "GMLBehaviorTree", 6 | "path": "folders/GMLBehaviorTree.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "__BTConfig", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /scripts/behavior_chase/BT_test.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "Scripts", 6 | "path": "folders/Scripts.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "BT_test", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /scripts/behavior_chase/behavior_chase.gml: -------------------------------------------------------------------------------- 1 | 2 | /// @param obj_ref 3 | /// @param range 4 | function TaskInstanceInRange(obj, range) : BTreeLeaf() constructor { 5 | name = "Task Instance In Range"; 6 | object_find = obj; 7 | range_limit = range; 8 | 9 | instance_ref = noone; 10 | 11 | /// @override 12 | static Init = function(){ 13 | instance_ref = instance_find(object_find, 0); 14 | } 15 | 16 | /// @override 17 | static Process = function(){ 18 | if(instance_exists(instance_ref) && point_distance(black_board_ref.user.x, black_board_ref.user.y, instance_ref.x, instance_ref.y) <= range_limit) 19 | return BTStates.Success; 20 | else 21 | return BTStates.Failure; 22 | } 23 | } 24 | 25 | /// @param speed 26 | /// @param timer_secs 27 | function TaskPatrolSimple(speed, timer_secs) : BTreeLeaf() constructor { 28 | name = "Taks Patrol Simple"; 29 | patrol_speed = speed; 30 | 31 | patrol_spd_x = 0; 32 | patrol_spd_y = 0; 33 | 34 | patrol_direction = 0; 35 | patrol_timer_max = timer_secs * room_speed; 36 | patrol_timer = 0; 37 | 38 | /// @override 39 | static Process = function(){ 40 | if(--patrol_timer <= 0){ 41 | patrol_direction = irandom(360); 42 | patrol_spd_x = lengthdir_x(patrol_speed, patrol_direction); 43 | patrol_spd_y = lengthdir_y(patrol_speed, patrol_direction); 44 | patrol_timer = patrol_timer_max; 45 | } 46 | 47 | black_board_ref.user.x += patrol_spd_x; 48 | black_board_ref.user.y += patrol_spd_y; 49 | return BTStates.Success; 50 | } 51 | } 52 | 53 | /// @param instance_chase 54 | /// @param speed_chase 55 | /// @param distance_max 56 | /// @param distance_min 57 | function TaskChaseInstance(instance_chase, speed_chase, distance_max, distance_min) : BTreeLeaf() constructor{ 58 | name = "Task Chase Instance"; 59 | 60 | chase_speed = speed_chase; 61 | instance_to_chase = instance_chase; 62 | distance_maximun_to_stop_chase = distance_max; 63 | distance_minimun_to_stop_chase = distance_min; 64 | 65 | ///@override 66 | static Process = function(){ 67 | if(instance_exists(instance_to_chase)){ 68 | 69 | // Check Stop chasing 70 | var _dist = point_distance(black_board_ref.user.x, black_board_ref.user.y, instance_to_chase.x, instance_to_chase.y); 71 | if(_dist <= distance_minimun_to_stop_chase) 72 | return BTStates.Success; 73 | else if (_dist >= distance_maximun_to_stop_chase) 74 | return BTStates.Failure; 75 | else { 76 | // Moving towards chasing 77 | var _dir = point_direction(black_board_ref.user.x, black_board_ref.user.y, instance_to_chase.x, instance_to_chase.y); 78 | black_board_ref.user.x += lengthdir_x(chase_speed, _dir); 79 | black_board_ref.user.y += lengthdir_y(chase_speed, _dir); 80 | 81 | return BTStates.Running; 82 | } 83 | } 84 | else 85 | return BTStates.Failure 86 | 87 | } 88 | 89 | } 90 | 91 | /// @param instance_target 92 | /// @param secs_between_hits 93 | function TaskMeleeHitTarget(instance_target, secs_preparation) : BTreeLeaf() constructor{ 94 | name = "Task Melee Hit on Target"; 95 | 96 | target_hit = instance_target; 97 | time_preparation_max = secs_preparation * room_speed; 98 | time_preparation = 0; 99 | 100 | /// @override 101 | static Process = function(){ 102 | if(!instance_exists(target_hit)) return BTStates.Failure; 103 | if(++time_preparation >= time_preparation_max){ 104 | time_preparation = 0; 105 | target_hit.life -= 10; 106 | return BTStates.Success; 107 | } 108 | else 109 | return BTStates.Running; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /scripts/behavior_chase/behavior_chase.yy: -------------------------------------------------------------------------------- 1 | { 2 | "isDnD": false, 3 | "isCompatibility": false, 4 | "parent": { 5 | "name": "example", 6 | "path": "folders/example.yy", 7 | }, 8 | "resourceVersion": "1.0", 9 | "name": "behavior_chase", 10 | "tags": [], 11 | "resourceType": "GMScript", 12 | } -------------------------------------------------------------------------------- /sprites/Sprite1/Sprite1.yy: -------------------------------------------------------------------------------- 1 | { 2 | "bboxMode": 0, 3 | "collisionKind": 1, 4 | "type": 0, 5 | "origin": 4, 6 | "preMultiplyAlpha": false, 7 | "edgeFiltering": false, 8 | "collisionTolerance": 0, 9 | "swfPrecision": 2.525, 10 | "bbox_left": 0, 11 | "bbox_right": 63, 12 | "bbox_top": 0, 13 | "bbox_bottom": 63, 14 | "HTile": false, 15 | "VTile": false, 16 | "For3D": false, 17 | "width": 64, 18 | "height": 64, 19 | "textureGroupId": { 20 | "name": "Default", 21 | "path": "texturegroups/Default", 22 | }, 23 | "swatchColours": null, 24 | "gridX": 0, 25 | "gridY": 0, 26 | "frames": [ 27 | {"compositeImage":{"FrameId":{"name":"d47c3ffb-aa12-4455-8cb7-22cd1be52178","path":"sprites/Sprite1/Sprite1.yy",},"LayerId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMSpriteBitmap",},"images":[ 28 | {"FrameId":{"name":"d47c3ffb-aa12-4455-8cb7-22cd1be52178","path":"sprites/Sprite1/Sprite1.yy",},"LayerId":{"name":"04284397-b0cd-4c59-8518-3ed983155443","path":"sprites/Sprite1/Sprite1.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMSpriteBitmap",}, 29 | ],"parent":{"name":"Sprite1","path":"sprites/Sprite1/Sprite1.yy",},"resourceVersion":"1.0","name":"d47c3ffb-aa12-4455-8cb7-22cd1be52178","tags":[],"resourceType":"GMSpriteFrame",}, 30 | ], 31 | "sequence": { 32 | "spriteId": {"name":"Sprite1","path":"sprites/Sprite1/Sprite1.yy",}, 33 | "timeUnits": 1, 34 | "playback": 1, 35 | "playbackSpeed": 30.0, 36 | "playbackSpeedType": 0, 37 | "autoRecord": true, 38 | "volume": 1.0, 39 | "length": 1.0, 40 | "events": {"Keyframes":[],"resourceVersion":"1.0","resourceType":"KeyframeStore",}, 41 | "moments": {"Keyframes":[],"resourceVersion":"1.0","resourceType":"KeyframeStore",}, 42 | "tracks": [ 43 | {"name":"frames","spriteId":null,"keyframes":{"Keyframes":[ 44 | {"id":"73222d53-7cb6-4681-ae3b-ba7ad31a08df","Key":0.0,"Length":1.0,"Stretch":false,"Disabled":false,"IsCreationKey":false,"Channels":{"0":{"Id":{"name":"d47c3ffb-aa12-4455-8cb7-22cd1be52178","path":"sprites/Sprite1/Sprite1.yy",},"resourceVersion":"1.0","resourceType":"SpriteFrameKeyframe",},},"resourceVersion":"1.0","resourceType":"Keyframe",}, 45 | ],"resourceVersion":"1.0","resourceType":"KeyframeStore",},"trackColour":0,"inheritsTrackColour":true,"builtinName":0,"traits":0,"interpolation":1,"tracks":[],"events":[],"modifiers":[],"isCreationTrack":false,"resourceVersion":"1.0","tags":[],"resourceType":"GMSpriteFramesTrack",}, 46 | ], 47 | "visibleRange": null, 48 | "lockOrigin": false, 49 | "showBackdrop": true, 50 | "showBackdropImage": false, 51 | "backdropImagePath": "", 52 | "backdropImageOpacity": 0.5, 53 | "backdropWidth": 1366, 54 | "backdropHeight": 768, 55 | "backdropXOffset": 0.0, 56 | "backdropYOffset": 0.0, 57 | "xorigin": 32, 58 | "yorigin": 32, 59 | "eventToFunction": {}, 60 | "eventStubScript": null, 61 | "parent": {"name":"Sprite1","path":"sprites/Sprite1/Sprite1.yy",}, 62 | "resourceVersion": "1.3", 63 | "name": "Sprite1", 64 | "tags": [], 65 | "resourceType": "GMSequence", 66 | }, 67 | "layers": [ 68 | {"visible":true,"isLocked":false,"blendMode":0,"opacity":100.0,"displayName":"default","resourceVersion":"1.0","name":"04284397-b0cd-4c59-8518-3ed983155443","tags":[],"resourceType":"GMImageLayer",}, 69 | ], 70 | "nineSlice": null, 71 | "parent": { 72 | "name": "example", 73 | "path": "folders/example.yy", 74 | }, 75 | "resourceVersion": "1.0", 76 | "name": "Sprite1", 77 | "tags": [], 78 | "resourceType": "GMSprite", 79 | } -------------------------------------------------------------------------------- /sprites/Sprite1/d47c3ffb-aa12-4455-8cb7-22cd1be52178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/sprites/Sprite1/d47c3ffb-aa12-4455-8cb7-22cd1be52178.png -------------------------------------------------------------------------------- /sprites/Sprite1/layers/d47c3ffb-aa12-4455-8cb7-22cd1be52178/04284397-b0cd-4c59-8518-3ed983155443.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/sprites/Sprite1/layers/d47c3ffb-aa12-4455-8cb7-22cd1be52178/04284397-b0cd-4c59-8518-3ed983155443.png -------------------------------------------------------------------------------- /sprites/Sprite2/9c751507-4992-43c3-9dde-795606e8c68d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/sprites/Sprite2/9c751507-4992-43c3-9dde-795606e8c68d.png -------------------------------------------------------------------------------- /sprites/Sprite2/Sprite2.yy: -------------------------------------------------------------------------------- 1 | { 2 | "bboxMode": 0, 3 | "collisionKind": 1, 4 | "type": 0, 5 | "origin": 4, 6 | "preMultiplyAlpha": false, 7 | "edgeFiltering": false, 8 | "collisionTolerance": 0, 9 | "swfPrecision": 2.525, 10 | "bbox_left": 0, 11 | "bbox_right": 63, 12 | "bbox_top": 0, 13 | "bbox_bottom": 63, 14 | "HTile": false, 15 | "VTile": false, 16 | "For3D": false, 17 | "width": 64, 18 | "height": 64, 19 | "textureGroupId": { 20 | "name": "Default", 21 | "path": "texturegroups/Default", 22 | }, 23 | "swatchColours": null, 24 | "gridX": 0, 25 | "gridY": 0, 26 | "frames": [ 27 | {"compositeImage":{"FrameId":{"name":"9c751507-4992-43c3-9dde-795606e8c68d","path":"sprites/Sprite2/Sprite2.yy",},"LayerId":null,"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMSpriteBitmap",},"images":[ 28 | {"FrameId":{"name":"9c751507-4992-43c3-9dde-795606e8c68d","path":"sprites/Sprite2/Sprite2.yy",},"LayerId":{"name":"4fdad78a-d4c5-4cdc-8b18-9a23df9ac50a","path":"sprites/Sprite2/Sprite2.yy",},"resourceVersion":"1.0","name":"","tags":[],"resourceType":"GMSpriteBitmap",}, 29 | ],"parent":{"name":"Sprite2","path":"sprites/Sprite2/Sprite2.yy",},"resourceVersion":"1.0","name":"9c751507-4992-43c3-9dde-795606e8c68d","tags":[],"resourceType":"GMSpriteFrame",}, 30 | ], 31 | "sequence": { 32 | "spriteId": {"name":"Sprite2","path":"sprites/Sprite2/Sprite2.yy",}, 33 | "timeUnits": 1, 34 | "playback": 1, 35 | "playbackSpeed": 30.0, 36 | "playbackSpeedType": 0, 37 | "autoRecord": true, 38 | "volume": 1.0, 39 | "length": 1.0, 40 | "events": {"Keyframes":[],"resourceVersion":"1.0","resourceType":"KeyframeStore",}, 41 | "moments": {"Keyframes":[],"resourceVersion":"1.0","resourceType":"KeyframeStore",}, 42 | "tracks": [ 43 | {"name":"frames","spriteId":null,"keyframes":{"Keyframes":[ 44 | {"id":"1684f6c8-91ac-4171-a9c7-fa74fc53b85a","Key":0.0,"Length":1.0,"Stretch":false,"Disabled":false,"IsCreationKey":false,"Channels":{"0":{"Id":{"name":"9c751507-4992-43c3-9dde-795606e8c68d","path":"sprites/Sprite2/Sprite2.yy",},"resourceVersion":"1.0","resourceType":"SpriteFrameKeyframe",},},"resourceVersion":"1.0","resourceType":"Keyframe",}, 45 | ],"resourceVersion":"1.0","resourceType":"KeyframeStore",},"trackColour":0,"inheritsTrackColour":true,"builtinName":0,"traits":0,"interpolation":1,"tracks":[],"events":[],"modifiers":[],"isCreationTrack":false,"resourceVersion":"1.0","tags":[],"resourceType":"GMSpriteFramesTrack",}, 46 | ], 47 | "visibleRange": null, 48 | "lockOrigin": false, 49 | "showBackdrop": true, 50 | "showBackdropImage": false, 51 | "backdropImagePath": "", 52 | "backdropImageOpacity": 0.5, 53 | "backdropWidth": 1366, 54 | "backdropHeight": 768, 55 | "backdropXOffset": 0.0, 56 | "backdropYOffset": 0.0, 57 | "xorigin": 32, 58 | "yorigin": 32, 59 | "eventToFunction": {}, 60 | "eventStubScript": null, 61 | "parent": {"name":"Sprite2","path":"sprites/Sprite2/Sprite2.yy",}, 62 | "resourceVersion": "1.3", 63 | "name": "Sprite2", 64 | "tags": [], 65 | "resourceType": "GMSequence", 66 | }, 67 | "layers": [ 68 | {"visible":true,"isLocked":false,"blendMode":0,"opacity":100.0,"displayName":"default","resourceVersion":"1.0","name":"4fdad78a-d4c5-4cdc-8b18-9a23df9ac50a","tags":[],"resourceType":"GMImageLayer",}, 69 | ], 70 | "nineSlice": null, 71 | "parent": { 72 | "name": "example", 73 | "path": "folders/example.yy", 74 | }, 75 | "resourceVersion": "1.0", 76 | "name": "Sprite2", 77 | "tags": [], 78 | "resourceType": "GMSprite", 79 | } -------------------------------------------------------------------------------- /sprites/Sprite2/layers/9c751507-4992-43c3-9dde-795606e8c68d/4fdad78a-d4c5-4cdc-8b18-9a23df9ac50a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitorestevam/GML-Behavior-Tree/49ae7e350fad426700e59fe7718aa3397a1a410a/sprites/Sprite2/layers/9c751507-4992-43c3-9dde-795606e8c68d/4fdad78a-d4c5-4cdc-8b18-9a23df9ac50a.png --------------------------------------------------------------------------------