From d0ff58052d59670a3cf168591a886779e4ca8fcf Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Thu, 1 Feb 2024 12:36:05 +0100 Subject: [PATCH] Demo: Add AI for ranged enemy --- demo/demo/agents/agent_ranged.tscn | 22 +++- ...et_flank_pos.gd => select_flanking_pos.gd} | 30 ++++- demo/demo/ai/trees/enemy_melee_nuanced.tres | 20 +-- demo/demo/ai/trees/enemy_melee_simple.tres | 1 - demo/demo/ai/trees/enemy_ranged.tres | 119 ++++++++++++++++++ demo/demo/scenes/demo.tscn | 6 +- 6 files changed, 176 insertions(+), 22 deletions(-) rename demo/demo/ai/tasks/{get_flank_pos.gd => select_flanking_pos.gd} (55%) create mode 100644 demo/demo/ai/trees/enemy_ranged.tres diff --git a/demo/demo/agents/agent_ranged.tscn b/demo/demo/agents/agent_ranged.tscn index 4a52945..311fa90 100644 --- a/demo/demo/agents/agent_ranged.tscn +++ b/demo/demo/agents/agent_ranged.tscn @@ -1,17 +1,25 @@ -[gd_scene load_steps=3 format=3 uid="uid://ci3x5esepbu5v"] +[gd_scene load_steps=5 format=3 uid="uid://ci3x5esepbu5v"] [ext_resource type="PackedScene" uid="uid://ooigbfhfy4wa" path="res://demo/agents/agent_base.tscn" id="1_oa4xm"] [ext_resource type="Texture2D" uid="uid://cjts4ennjtepg" path="res://demo/assets/agent_ranged.png" id="2_37lvn"] +[ext_resource type="BehaviorTree" uid="uid://cqluon1y1hnn5" path="res://demo/ai/trees/enemy_ranged.tres" id="3_f7r5w"] -[node name="Bobby" instance=ExtResource("1_oa4xm")] +[sub_resource type="BlackboardPlan" id="BlackboardPlan_2kwy7"] +var/speed/name = "speed" +var/speed/type = 3 +var/speed/value = 400.0 +var/speed/hint = 1 +var/speed/hint_string = "10,1000,10" -[node name="LegL" parent="Root/Rig" index="0"] +[node name="AgentRanged" instance=ExtResource("1_oa4xm")] + +[node name="LegL" parent="Root/Rig" index="1"] texture = ExtResource("2_37lvn") -[node name="LegR" parent="Root/Rig" index="1"] +[node name="LegR" parent="Root/Rig" index="2"] texture = ExtResource("2_37lvn") -[node name="Body" parent="Root/Rig" index="2"] +[node name="Body" parent="Root/Rig" index="3"] texture = ExtResource("2_37lvn") [node name="Hat" parent="Root/Rig/Body" index="0"] @@ -22,3 +30,7 @@ texture = ExtResource("2_37lvn") [node name="HandR" parent="Root/Rig/Body" index="2"] texture = ExtResource("2_37lvn") + +[node name="BTPlayer" type="BTPlayer" parent="." index="4"] +behavior_tree = ExtResource("3_f7r5w") +blackboard_plan = SubResource("BlackboardPlan_2kwy7") diff --git a/demo/demo/ai/tasks/get_flank_pos.gd b/demo/demo/ai/tasks/select_flanking_pos.gd similarity index 55% rename from demo/demo/ai/tasks/get_flank_pos.gd rename to demo/demo/ai/tasks/select_flanking_pos.gd index 776a8c8..37186a6 100644 --- a/demo/demo/ai/tasks/get_flank_pos.gd +++ b/demo/demo/ai/tasks/select_flanking_pos.gd @@ -1,5 +1,5 @@ #* -#* GetFlankPos.gd +#* select_flanking_pos.gd #* ============================================================================= #* Copyright 2021-2024 Serhii Snitsaruk #* @@ -10,25 +10,43 @@ #* @tool extends BTAction -## GetFlankPos +## SelectFlankingPos on the side of a target, and return SUCCESS. +## Returns FAILURE, if the target is not valid. +## Blackboard variable that holds current target (should be a Node2D instance). @export var target_var: String = "_target" + +## Should closest side be selected? +@export var closest_side: bool = false + +## Minimum range relative to the target. +@export var range_min: int = 300 + +## Maximum range relative to the target. +@export var range_max: int = 400 + +## Blackboard variable that will be used to store selected position. @export var position_var: String = "flank_pos" -@export var distance: float = 300.0 # Display a customized name (requires @tool). func _generate_name() -> String: - return "GetFlankPos %s -> %s" % [ + return "SelectFlankingPos target: %s range: [%s, %s] closest: %s ➜ %s" % [ LimboUtility.decorate_var(target_var), + range_min, + range_max, + closest_side, LimboUtility.decorate_var(position_var)] # Called each time this task is ticked (aka executed). func _tick(_delta: float) -> Status: - var target: CharacterBody2D = blackboard.get_var(target_var) + var target := blackboard.get_var(target_var) as Node2D if not is_instance_valid(target): return FAILURE + var dir: float = signf(target.global_position.x - agent.global_position.x) + if closest_side: + dir *= -1.0 var flank_pos: Vector2 = target.global_position - flank_pos.x += dir * distance + flank_pos.x += dir * randf_range(range_min, range_max) blackboard.set_var(position_var, flank_pos) return SUCCESS diff --git a/demo/demo/ai/trees/enemy_melee_nuanced.tres b/demo/demo/ai/trees/enemy_melee_nuanced.tres index e9782e2..def8f9d 100644 --- a/demo/demo/ai/trees/enemy_melee_nuanced.tres +++ b/demo/demo/ai/trees/enemy_melee_nuanced.tres @@ -1,8 +1,8 @@ [gd_resource type="BehaviorTree" load_steps=40 format=3 uid="uid://c2u6sljqkim0n"] [ext_resource type="Script" path="res://demo/ai/tasks/get_first_in_group.gd" id="1_uvue5"] -[ext_resource type="Script" path="res://demo/ai/tasks/get_flank_pos.gd" id="2_0llce"] [ext_resource type="Script" path="res://demo/ai/tasks/pursue.gd" id="2_aanv5"] +[ext_resource type="Script" path="res://demo/ai/tasks/select_flanking_pos.gd" id="2_fl3fr"] [ext_resource type="Script" path="res://demo/ai/tasks/face_target.gd" id="3_r5itf"] [ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_x6gkn"] @@ -40,12 +40,6 @@ output_var = "_target" custom_name = "Pause before action" children = [SubResource("BTPlayAnimation_qiw21"), SubResource("BTRandomWait_xlud8"), SubResource("BTAction_c4cxo")] -[sub_resource type="BTAction" id="BTAction_qr6nr"] -script = ExtResource("2_0llce") -target_var = "_target" -position_var = "_flank_pos" -distance = 450.0 - [sub_resource type="BBNode" id="BBNode_kc64r"] saved_value = NodePath("AnimationPlayer") resource_name = "AnimationPlayer" @@ -56,6 +50,14 @@ animation_name = &"walk" blend = 0.1 speed = 1.5 +[sub_resource type="BTAction" id="BTAction_6e48s"] +script = ExtResource("2_fl3fr") +target_var = "_target" +closest_side = false +range_min = 400.0 +range_max = 600.0 +position_var = "_flank_pos" + [sub_resource type="BTAction" id="BTAction_66hsk"] script = ExtResource("3_x6gkn") target_position_var = "_flank_pos" @@ -71,11 +73,11 @@ target_var = "_target" [sub_resource type="BTSequence" id="BTSequence_lhg7f"] custom_name = "Flank player" -children = [SubResource("BTAction_qr6nr"), SubResource("BTPlayAnimation_panch"), SubResource("BTTimeLimit_24ath"), SubResource("BTAction_enw2m")] +children = [SubResource("BTPlayAnimation_panch"), SubResource("BTAction_6e48s"), SubResource("BTTimeLimit_24ath"), SubResource("BTAction_enw2m")] metadata/_weight_ = 1.0 [sub_resource type="BTCooldown" id="BTCooldown_skw41"] -duration = 5.0 +duration = 6.0 children = [SubResource("BTSequence_lhg7f")] metadata/_weight_ = 2.0 diff --git a/demo/demo/ai/trees/enemy_melee_simple.tres b/demo/demo/ai/trees/enemy_melee_simple.tres index d3b38af..3465280 100644 --- a/demo/demo/ai/trees/enemy_melee_simple.tres +++ b/demo/demo/ai/trees/enemy_melee_simple.tres @@ -77,7 +77,6 @@ custom_name = "Melee attack" children = [SubResource("BTAction_kidxn"), SubResource("BTWait_tadkc"), SubResource("BTPlayAnimation_ppmxd")] [sub_resource type="BTSequence" id="BTSequence_pxl2k"] -custom_name = "Main" children = [SubResource("BTSequence_yhjh1"), SubResource("BTSequence_1xfnq"), SubResource("BTSequence_ww5v2")] [resource] diff --git a/demo/demo/ai/trees/enemy_ranged.tres b/demo/demo/ai/trees/enemy_ranged.tres new file mode 100644 index 0000000..9d82ecf --- /dev/null +++ b/demo/demo/ai/trees/enemy_ranged.tres @@ -0,0 +1,119 @@ +[gd_resource type="BehaviorTree" load_steps=29 format=3 uid="uid://cqluon1y1hnn5"] + +[ext_resource type="Script" path="res://demo/ai/tasks/get_first_in_group.gd" id="1_3j1v8"] +[ext_resource type="Script" path="res://demo/ai/tasks/select_flanking_pos.gd" id="2_vbh52"] +[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_20ffh"] +[ext_resource type="Script" path="res://demo/ai/tasks/face_target.gd" id="4_x8yor"] + +[sub_resource type="BlackboardPlan" id="BlackboardPlan_46tbn"] +var/speed/name = "speed" +var/speed/type = 3 +var/speed/value = 400.0 +var/speed/hint = 1 +var/speed/hint_string = "10,1000,10" + +[sub_resource type="BBNode" id="BBNode_nrd4b"] +saved_value = NodePath("AnimationPlayer") +resource_name = "AnimationPlayer" + +[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_qiw21"] +animation_player = SubResource("BBNode_nrd4b") +animation_name = &"idle" +blend = 0.1 + +[sub_resource type="BTRandomWait" id="BTRandomWait_xlud8"] +min_duration = 1.2 +max_duration = 2.5 + +[sub_resource type="BTAction" id="BTAction_c4cxo"] +script = ExtResource("1_3j1v8") +group = &"player" +output_var = "_target" + +[sub_resource type="BTSequence" id="BTSequence_yhjh1"] +custom_name = "Take a break" +children = [SubResource("BTPlayAnimation_qiw21"), SubResource("BTRandomWait_xlud8"), SubResource("BTAction_c4cxo")] + +[sub_resource type="BTAction" id="BTAction_kuuw2"] +script = ExtResource("2_vbh52") +target_var = "_target" +closest_side = true +range_min = 400.0 +range_max = 1000.0 +position_var = "_shoot_pos" + +[sub_resource type="BBNode" id="BBNode_kc64r"] +saved_value = NodePath("AnimationPlayer") +resource_name = "AnimationPlayer" + +[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_panch"] +animation_player = SubResource("BBNode_kc64r") +animation_name = &"walk" +blend = 0.1 + +[sub_resource type="BTAction" id="BTAction_66hsk"] +script = ExtResource("3_20ffh") +target_position_var = "_shoot_pos" +speed_var = "speed" +tolerance = 50.0 + +[sub_resource type="BTTimeLimit" id="BTTimeLimit_24ath"] +children = [SubResource("BTAction_66hsk")] + +[sub_resource type="BTAction" id="BTAction_enw2m"] +script = ExtResource("4_x8yor") +target_var = "_target" + +[sub_resource type="BTSequence" id="BTSequence_lhg7f"] +custom_name = "Reposition" +children = [SubResource("BTAction_kuuw2"), SubResource("BTPlayAnimation_panch"), SubResource("BTTimeLimit_24ath"), SubResource("BTAction_enw2m")] +metadata/_weight_ = 1.0 + +[sub_resource type="BBNode" id="BBNode_s6vt4"] +saved_value = NodePath("AnimationPlayer") +resource_name = "AnimationPlayer" + +[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_qa8jy"] +animation_player = SubResource("BBNode_s6vt4") +animation_name = &"throw_prepare" +blend = 0.1 + +[sub_resource type="BTWait" id="BTWait_gbcyb"] + +[sub_resource type="BBNode" id="BBNode_qkfqt"] +saved_value = NodePath("AnimationPlayer") +resource_name = "AnimationPlayer" + +[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_0ktds"] +await_completion = 1.0 +animation_player = SubResource("BBNode_qkfqt") +animation_name = &"throw" +blend = 0.05 + +[sub_resource type="BBNode" id="BBNode_1yxc5"] +saved_value = NodePath(".") +resource_name = "." + +[sub_resource type="BTCallMethod" id="BTCallMethod_yx4fk"] +node = SubResource("BBNode_1yxc5") +method = &"throw_ninja_star" + +[sub_resource type="BTWait" id="BTWait_d2ib4"] +duration = 0.2 + +[sub_resource type="BTSequence" id="BTSequence_rgbq3"] +custom_name = "Throw ninja star" +children = [SubResource("BTPlayAnimation_qa8jy"), SubResource("BTWait_gbcyb"), SubResource("BTPlayAnimation_0ktds"), SubResource("BTCallMethod_yx4fk"), SubResource("BTWait_d2ib4")] +metadata/_weight_ = 1.0 + +[sub_resource type="BTRepeat" id="BTRepeat_g08ia"] +times = 3 +children = [SubResource("BTSequence_rgbq3")] + +[sub_resource type="BTSequence" id="BTSequence_pxl2k"] +custom_name = "Main" +children = [SubResource("BTSequence_yhjh1"), SubResource("BTSequence_lhg7f"), SubResource("BTRepeat_g08ia")] + +[resource] +blackboard_plan = SubResource("BlackboardPlan_46tbn") +root_task = SubResource("BTSequence_pxl2k") diff --git a/demo/demo/scenes/demo.tscn b/demo/demo/scenes/demo.tscn index d8a8ff0..6f39d4c 100644 --- a/demo/demo/scenes/demo.tscn +++ b/demo/demo/scenes/demo.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=11 format=3 uid="uid://bsig1usigbbuy"] +[gd_scene load_steps=12 format=3 uid="uid://bsig1usigbbuy"] [ext_resource type="Texture2D" uid="uid://b3g14elmg0m36" path="res://demo/assets/env_rocks.png" id="1_145kx"] [ext_resource type="PackedScene" uid="uid://dt2jlrqffpyw" path="res://demo/scenes/clouds.tscn" id="1_gsxmp"] @@ -6,6 +6,7 @@ [ext_resource type="Texture2D" uid="uid://4kw2ks8doc0w" path="res://demo/assets/env_plants.png" id="2_kesm7"] [ext_resource type="PackedScene" uid="uid://bpd1wmw2f7bvg" path="res://demo/props/gong.tscn" id="3_nbto3"] [ext_resource type="PackedScene" uid="uid://d07ag5dcje13i" path="res://demo/agents/player/player.tscn" id="5_cmgoj"] +[ext_resource type="PackedScene" uid="uid://ci3x5esepbu5v" path="res://demo/agents/agent_ranged.tscn" id="6_76icr"] [ext_resource type="PackedScene" uid="uid://2e4ohaqjaawb" path="res://demo/agents/agent_melee_nuanced.tscn" id="8_ovfbp"] [sub_resource type="Animation" id="Animation_gwtgs"] @@ -2888,6 +2889,9 @@ drag_bottom_margin = 0.1 [node name="AgentMeleeNuanced" parent="YSort/Agents" instance=ExtResource("8_ovfbp")] position = Vector2(-180, 552) +[node name="AgentRanged" parent="YSort/Agents" instance=ExtResource("6_76icr")] +position = Vector2(2067, 543) + [node name="Props" type="Node2D" parent="YSort"] y_sort_enabled = true metadata/_edit_lock_ = true