Demo: Implement flanking for nuanced melee agent

Also add license info to the scripts.
This commit is contained in:
Serhii Snitsaruk 2024-01-31 19:26:25 +01:00
parent e9e582f251
commit 688a5416f2
19 changed files with 364 additions and 47 deletions

View File

@ -1,2 +0,0 @@
extends "res://demo/agents/scripts/agent_base.gd"

View File

@ -1,38 +0,0 @@
[gd_scene load_steps=6 format=3 uid="uid://sjans5psq6pg"]
[ext_resource type="PackedScene" uid="uid://ooigbfhfy4wa" path="res://demo/agents/agent_base.tscn" id="1_uffd7"]
[ext_resource type="BehaviorTree" uid="uid://bpdm5jnegi38" path="res://demo/ai/trees/enemy_melee_simple.tres" id="2_tmu02"]
[ext_resource type="Script" path="res://demo/agents/agent_base_enemy.gd" id="2_w7f5y"]
[ext_resource type="Texture2D" uid="uid://cw8s50856x8ct" path="res://demo/assets/agent_melee_simple.png" id="3_c30et"]
[sub_resource type="BlackboardPlan" id="BlackboardPlan_4e1gs"]
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="AgentEnemy" instance=ExtResource("1_uffd7")]
script = ExtResource("2_w7f5y")
[node name="LegL" parent="Root/Rig" index="0"]
texture = ExtResource("3_c30et")
[node name="LegR" parent="Root/Rig" index="1"]
texture = ExtResource("3_c30et")
[node name="Body" parent="Root/Rig" index="2"]
texture = ExtResource("3_c30et")
[node name="Hat" parent="Root/Rig/Body" index="0"]
texture = ExtResource("3_c30et")
[node name="HandL" parent="Root/Rig/Body" index="1"]
texture = ExtResource("3_c30et")
[node name="HandR" parent="Root/Rig/Body" index="2"]
texture = ExtResource("3_c30et")
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
behavior_tree = ExtResource("2_tmu02")
blackboard_plan = SubResource("BlackboardPlan_4e1gs")

View File

@ -1,9 +1,22 @@
[gd_scene load_steps=3 format=3 uid="uid://2e4ohaqjaawb"]
[gd_scene load_steps=5 format=3 uid="uid://2e4ohaqjaawb"]
[ext_resource type="PackedScene" uid="uid://ooigbfhfy4wa" path="res://demo/agents/agent_base.tscn" id="1_afx5l"]
[ext_resource type="Texture2D" uid="uid://usu3j55d6dgc" path="res://demo/assets/agent_melee_nuanced.png" id="2_e51r0"]
[ext_resource type="BehaviorTree" uid="uid://c2u6sljqkim0n" path="res://demo/ai/trees/enemy_melee_nuanced.tres" id="3_b8kcf"]
[node name="Bobby" instance=ExtResource("1_afx5l")]
[sub_resource type="BlackboardPlan" id="BlackboardPlan_tnf02"]
var/speed/name = "speed"
var/speed/type = 3
var/speed/value = 400.0
var/speed/hint = 1
var/speed/hint_string = "10,1000,10"
var/flank_speed/name = "flank_speed"
var/flank_speed/type = 3
var/flank_speed/value = 600.0
var/flank_speed/hint = 1
var/flank_speed/hint_string = "10,1000,10"
[node name="AgentMeleeNuanced" instance=ExtResource("1_afx5l")]
[node name="LegL" parent="Root/Rig" index="0"]
texture = ExtResource("2_e51r0")
@ -22,3 +35,7 @@ texture = ExtResource("2_e51r0")
[node name="HandR" parent="Root/Rig/Body" index="2"]
texture = ExtResource("2_e51r0")
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
behavior_tree = ExtResource("3_b8kcf")
blackboard_plan = SubResource("BlackboardPlan_tnf02")

View File

@ -1,7 +1,15 @@
[gd_scene load_steps=3 format=3 uid="uid://comfxjrcylgb"]
[gd_scene load_steps=5 format=3 uid="uid://comfxjrcylgb"]
[ext_resource type="PackedScene" uid="uid://ooigbfhfy4wa" path="res://demo/agents/agent_base.tscn" id="1_l180o"]
[ext_resource type="Texture2D" uid="uid://cw8s50856x8ct" path="res://demo/assets/agent_melee_simple.png" id="2_bvbes"]
[ext_resource type="BehaviorTree" uid="uid://bpdm5jnegi38" path="res://demo/ai/trees/enemy_melee_simple.tres" id="3_tb7cx"]
[sub_resource type="BlackboardPlan" id="BlackboardPlan_jbvam"]
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="AgentMeleeSimple" instance=ExtResource("1_l180o")]
@ -22,3 +30,7 @@ texture = ExtResource("2_bvbes")
[node name="HandR" parent="Root/Rig/Body" index="2"]
texture = ExtResource("2_bvbes")
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
behavior_tree = ExtResource("3_tb7cx")
blackboard_plan = SubResource("BlackboardPlan_jbvam")

View File

@ -1,3 +1,13 @@
#*
#* player.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
extends "res://demo/agents/scripts/agent_base.gd"
## Player.

View File

@ -1,3 +1,13 @@
#*
#* attack_state.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
extends LimboState
## Attack state: Perform 3-part combo attack for as long as player hits attack button.

View File

@ -1,3 +1,13 @@
#*
#* idle_state.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
extends LimboState
## Idle state.

View File

@ -1,3 +1,13 @@
#*
#* move_state.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
extends LimboState
## Move state.

View File

@ -1,3 +1,13 @@
#*
#* agent_base.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
extends CharacterBody2D
## Base agent script.

View File

@ -1,3 +1,13 @@
#*
#* health.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
class_name Health
extends Node
## Tracks health and emits signal when damaged or dead.

View File

@ -1,3 +1,13 @@
#*
#* hitbox.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
class_name Hitbox
extends Area2D
## Area that deals damage.

View File

@ -1,3 +1,13 @@
#*
#* hurtbox.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
class_name Hurtbox
extends Area2D
## Area that registers damage.

View File

@ -0,0 +1,39 @@
#*
#* arrive_pos.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
@tool
extends BTAction
## Arrive to a position, with a bias to horizontal movement.
@export var target_position_var := "target_position"
@export var speed_var := "speed"
@export var tolerance := 50.0
func _generate_name() -> String:
return "Arrive pos: %s" % [
LimboUtility.decorate_var(target_position_var),
]
func _tick(p_delta: float) -> Status:
var target_pos: Vector2 = blackboard.get_var(target_position_var, Vector2.ZERO)
if target_pos.distance_to(agent.global_position) < tolerance:
return SUCCESS
var speed: float = blackboard.get_var(speed_var, 10.0)
var dist: float = agent.global_position.distance_to(target_pos)
var vertical_factor: float = remap(dist, 200.0, 500.0, 1.0, 0.0)
vertical_factor = clampf(vertical_factor, 0.0, 1.0)
var dir: Vector2 = agent.global_position.direction_to(target_pos)
dir.y *= vertical_factor
agent.velocity = dir.normalized() * speed
agent.move_and_slide()
return RUNNING

View File

@ -1,3 +1,13 @@
#*
#* face_target.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
@tool
extends BTAction
## FaceTarget

View File

@ -1,3 +1,13 @@
#*
#* get_first_in_group.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
@tool
extends BTAction

View File

@ -0,0 +1,34 @@
#*
#* GetFlankPos.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
@tool
extends BTAction
## GetFlankPos
@export var target_var: String = "_target"
@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" % [
LimboUtility.decorate_var(target_var),
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)
if not is_instance_valid(target):
return FAILURE
var dir: float = signf(target.global_position.x - agent.global_position.x)
var flank_pos: Vector2 = target.global_position
flank_pos.x += dir * distance
blackboard.set_var(position_var, flank_pos)
return SUCCESS

View File

@ -1,3 +1,13 @@
#*
#* pursue.gd
#* =============================================================================
#* Copyright 2021-2024 Serhii Snitsaruk
#*
#* Use of this source code is governed by an MIT-style
#* license that can be found in the LICENSE file or at
#* https://opensource.org/licenses/MIT.
#* =============================================================================
#*
@tool
extends BTAction
## Pursue target.
@ -35,6 +45,7 @@ func _tick(_delta: float) -> Status:
var target_pos := Vector2(
target.global_position.x + approach_distance * _side,
target.global_position.y)
if agent.global_position.distance_to(target_pos) < TOLERANCE:
return SUCCESS

View File

@ -0,0 +1,144 @@
[gd_resource type="BehaviorTree" load_steps=34 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/face_target.gd" id="3_r5itf"]
[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_x6gkn"]
[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"
var/flank_speed/name = "flank_speed"
var/flank_speed/type = 3
var/flank_speed/value = 600.0
var/flank_speed/hint = 1
var/flank_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 = 0.7
max_duration = 1.5
[sub_resource type="BTSequence" id="BTSequence_yhjh1"]
custom_name = "Pause before action"
children = [SubResource("BTPlayAnimation_qiw21"), SubResource("BTRandomWait_xlud8")]
[sub_resource type="BTAction" id="BTAction_c4cxo"]
script = ExtResource("1_uvue5")
group = &"player"
output_var = "_target"
[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"
[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_panch"]
animation_player = SubResource("BBNode_kc64r")
animation_name = &"walk"
blend = 0.1
speed = 1.5
[sub_resource type="BTAction" id="BTAction_66hsk"]
script = ExtResource("3_x6gkn")
target_position_var = "_flank_pos"
speed_var = "flank_speed"
tolerance = 50.0
[sub_resource type="BTTimeLimit" id="BTTimeLimit_24ath"]
time_limit = 10.0
children = [SubResource("BTAction_66hsk")]
[sub_resource type="BTAction" id="BTAction_enw2m"]
script = ExtResource("3_r5itf")
target_var = "_target"
[sub_resource type="BTSequence" id="BTSequence_lhg7f"]
custom_name = "Flank player"
children = [SubResource("BTAction_c4cxo"), SubResource("BTAction_qr6nr"), SubResource("BTPlayAnimation_panch"), SubResource("BTTimeLimit_24ath"), SubResource("BTAction_enw2m")]
metadata/_weight_ = 1.0
[sub_resource type="BTCooldown" id="BTCooldown_skw41"]
duration = 5.0
children = [SubResource("BTSequence_lhg7f")]
[sub_resource type="BBNode" id="BBNode_wpj6d"]
saved_value = NodePath("AnimationPlayer")
resource_name = "AnimationPlayer"
[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_olf37"]
animation_player = SubResource("BBNode_wpj6d")
animation_name = &"walk"
blend = 0.1
[sub_resource type="BTAction" id="BTAction_ulbrf"]
script = ExtResource("1_uvue5")
group = &"player"
output_var = "_target"
[sub_resource type="BTAction" id="BTAction_a4jqi"]
script = ExtResource("2_aanv5")
target_var = "_target"
speed_var = "speed"
approach_distance = 100.0
[sub_resource type="BTTimeLimit" id="BTTimeLimit_xek5v"]
time_limit = 2.0
children = [SubResource("BTAction_a4jqi")]
[sub_resource type="BTSequence" id="BTSequence_vd4xt"]
custom_name = "Approach"
children = [SubResource("BTPlayAnimation_olf37"), SubResource("BTAction_ulbrf"), SubResource("BTTimeLimit_xek5v")]
[sub_resource type="BTAction" id="BTAction_kidxn"]
script = ExtResource("3_r5itf")
target_var = "_target"
[sub_resource type="BTWait" id="BTWait_tadkc"]
duration = 0.1
[sub_resource type="BBNode" id="BBNode_s8evu"]
saved_value = NodePath("AnimationPlayer")
resource_name = "AnimationPlayer"
[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_ppmxd"]
await_completion = 2.0
animation_player = SubResource("BBNode_s8evu")
animation_name = &"attack_3"
[sub_resource type="BTSequence" id="BTSequence_ww5v2"]
custom_name = "Melee attack"
children = [SubResource("BTAction_kidxn"), SubResource("BTWait_tadkc"), SubResource("BTPlayAnimation_ppmxd")]
[sub_resource type="BTSequence" id="BTSequence_1xfnq"]
custom_name = "Approach and melee attack"
children = [SubResource("BTSequence_vd4xt"), SubResource("BTSequence_ww5v2")]
[sub_resource type="BTProbabilitySelector" id="BTProbabilitySelector_rjsiq"]
abort_on_failure = true
children = [SubResource("BTCooldown_skw41"), SubResource("BTSequence_1xfnq")]
[sub_resource type="BTSequence" id="BTSequence_pxl2k"]
custom_name = "Main"
children = [SubResource("BTSequence_yhjh1"), SubResource("BTProbabilitySelector_rjsiq")]
[resource]
blackboard_plan = SubResource("BlackboardPlan_46tbn")
root_task = SubResource("BTSequence_pxl2k")

View File

@ -6,7 +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://sjans5psq6pg" path="res://demo/agents/agent_base_enemy.tscn" id="5_knyss"]
[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"]
length = 0.001
@ -2872,9 +2872,6 @@ metadata/_edit_lock_ = true
y_sort_enabled = true
metadata/_edit_lock_ = true
[node name="AgentEnemy" parent="YSort/Agents" instance=ExtResource("5_knyss")]
position = Vector2(1527.4, 690.665)
[node name="Player" parent="YSort/Agents" instance=ExtResource("5_cmgoj")]
position = Vector2(633, 256)
@ -2888,6 +2885,9 @@ drag_vertical_enabled = true
drag_top_margin = 0.1
drag_bottom_margin = 0.1
[node name="AgentMeleeNuanced" parent="YSort/Agents" instance=ExtResource("8_ovfbp")]
position = Vector2(-180, 552)
[node name="Props" type="Node2D" parent="YSort"]
y_sort_enabled = true
metadata/_edit_lock_ = true