Demo: Refactoring, docstrings and tweaks
This commit is contained in:
parent
c925bab659
commit
7949330c90
|
@ -4,7 +4,7 @@
|
||||||
[ext_resource type="Texture2D" uid="uid://ce16nc0wy2s8" path="res://demo/assets/agent_charger.png" id="2_y7pic"]
|
[ext_resource type="Texture2D" uid="uid://ce16nc0wy2s8" path="res://demo/assets/agent_charger.png" id="2_y7pic"]
|
||||||
[ext_resource type="BehaviorTree" uid="uid://ylife72ym5et" path="res://demo/ai/trees/02_agent_charger.tres" id="3_nacc3"]
|
[ext_resource type="BehaviorTree" uid="uid://ylife72ym5et" path="res://demo/ai/trees/02_agent_charger.tres" id="3_nacc3"]
|
||||||
|
|
||||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_b4r3u"]
|
[sub_resource type="BlackboardPlan" id="BlackboardPlan_pmyhf"]
|
||||||
var/speed/name = "speed"
|
var/speed/name = "speed"
|
||||||
var/speed/type = 3
|
var/speed/type = 3
|
||||||
var/speed/value = 400.0
|
var/speed/value = 400.0
|
||||||
|
@ -12,7 +12,7 @@ var/speed/hint = 1
|
||||||
var/speed/hint_string = "10,1000,10"
|
var/speed/hint_string = "10,1000,10"
|
||||||
var/charge_speed/name = "charge_speed"
|
var/charge_speed/name = "charge_speed"
|
||||||
var/charge_speed/type = 3
|
var/charge_speed/type = 3
|
||||||
var/charge_speed/value = 800.0
|
var/charge_speed/value = 1000.0
|
||||||
var/charge_speed/hint = 1
|
var/charge_speed/hint = 1
|
||||||
var/charge_speed/hint_string = "10,1000,10"
|
var/charge_speed/hint_string = "10,1000,10"
|
||||||
|
|
||||||
|
@ -38,4 +38,4 @@ texture = ExtResource("2_y7pic")
|
||||||
|
|
||||||
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
|
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
|
||||||
behavior_tree = ExtResource("3_nacc3")
|
behavior_tree = ExtResource("3_nacc3")
|
||||||
blackboard_plan = SubResource("BlackboardPlan_b4r3u")
|
blackboard_plan = SubResource("BlackboardPlan_pmyhf")
|
||||||
|
|
|
@ -4,12 +4,17 @@
|
||||||
[ext_resource type="Texture2D" uid="uid://bo0ibp7tvjbba" path="res://demo/assets/agent_combo.png" id="2_4rqld"]
|
[ext_resource type="Texture2D" uid="uid://bo0ibp7tvjbba" path="res://demo/assets/agent_combo.png" id="2_4rqld"]
|
||||||
[ext_resource type="BehaviorTree" uid="uid://cpncl1db8j12f" path="res://demo/ai/trees/06_agent_melee_combo.tres" id="3_l805q"]
|
[ext_resource type="BehaviorTree" uid="uid://cpncl1db8j12f" path="res://demo/ai/trees/06_agent_melee_combo.tres" id="3_l805q"]
|
||||||
|
|
||||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_78rmu"]
|
[sub_resource type="BlackboardPlan" id="BlackboardPlan_67ric"]
|
||||||
var/speed/name = "speed"
|
var/speed/name = "speed"
|
||||||
var/speed/type = 3
|
var/speed/type = 3
|
||||||
var/speed/value = 400.0
|
var/speed/value = 400.0
|
||||||
var/speed/hint = 1
|
var/speed/hint = 1
|
||||||
var/speed/hint_string = "10,1000,10"
|
var/speed/hint_string = "10,1000,10"
|
||||||
|
var/charge_speed/name = "charge_speed"
|
||||||
|
var/charge_speed/type = 3
|
||||||
|
var/charge_speed/value = 1000.0
|
||||||
|
var/charge_speed/hint = 0
|
||||||
|
var/charge_speed/hint_string = ""
|
||||||
|
|
||||||
[node name="AgentMeleeCombo" instance=ExtResource("1_dny3b")]
|
[node name="AgentMeleeCombo" instance=ExtResource("1_dny3b")]
|
||||||
|
|
||||||
|
@ -31,11 +36,9 @@ texture = ExtResource("2_4rqld")
|
||||||
[node name="HandR" parent="Root/Rig/Body" index="2"]
|
[node name="HandR" parent="Root/Rig/Body" index="2"]
|
||||||
texture = ExtResource("2_4rqld")
|
texture = ExtResource("2_4rqld")
|
||||||
|
|
||||||
[node name="WeaponNinjaStar" parent="Root" index="2"]
|
[node name="WeaponNinjaStar" parent="Root" index="1"]
|
||||||
position = Vector2(-55, -76)
|
|
||||||
rotation = 0.0
|
|
||||||
scale = Vector2(0.999983, 0.999976)
|
scale = Vector2(0.999983, 0.999976)
|
||||||
|
|
||||||
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
|
[node name="BTPlayer" type="BTPlayer" parent="." index="4"]
|
||||||
behavior_tree = ExtResource("3_l805q")
|
behavior_tree = ExtResource("3_l805q")
|
||||||
blackboard_plan = SubResource("BlackboardPlan_78rmu")
|
blackboard_plan = SubResource("BlackboardPlan_67ric")
|
||||||
|
|
|
@ -10,9 +10,12 @@
|
||||||
#*
|
#*
|
||||||
extends CharacterBody2D
|
extends CharacterBody2D
|
||||||
|
|
||||||
## Base agent script.
|
## Base agent script that is shared by all agents.
|
||||||
|
|
||||||
|
# Resource file to use in summon_minion() method.
|
||||||
const MINION_RESOURCE := "res://demo/agents/03_agent_imp.tscn"
|
const MINION_RESOURCE := "res://demo/agents/03_agent_imp.tscn"
|
||||||
|
|
||||||
|
# Projectile resource.
|
||||||
const NinjaStar := preload("res://demo/agents/ninja_star/ninja_star.tscn")
|
const NinjaStar := preload("res://demo/agents/ninja_star/ninja_star.tscn")
|
||||||
const Fireball := preload("res://demo/agents/fireball/fireball.tscn")
|
const Fireball := preload("res://demo/agents/fireball/fireball.tscn")
|
||||||
|
|
||||||
|
@ -22,21 +25,21 @@ const Fireball := preload("res://demo/agents/fireball/fireball.tscn")
|
||||||
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
|
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
|
||||||
@onready var summoning_effect: GPUParticles2D = $FX/Summoned
|
@onready var summoning_effect: GPUParticles2D = $FX/Summoned
|
||||||
|
|
||||||
|
|
||||||
var _frames_since_facing_update: int = 0
|
var _frames_since_facing_update: int = 0
|
||||||
var _is_dead: bool = false
|
var _is_dead: bool = false
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
health.damaged.connect(_damaged)
|
health.damaged.connect(_damaged)
|
||||||
health.death.connect(die)
|
health.death.connect(die)
|
||||||
|
|
||||||
|
## Update agent's facing in the velocity direction.
|
||||||
func update_facing() -> void:
|
func update_facing() -> void:
|
||||||
_frames_since_facing_update += 1
|
_frames_since_facing_update += 1
|
||||||
if _frames_since_facing_update > 3:
|
if _frames_since_facing_update > 3:
|
||||||
face_dir(velocity.x)
|
face_dir(velocity.x)
|
||||||
|
|
||||||
|
## Face specified direction.
|
||||||
func face_dir(dir: float) -> void:
|
func face_dir(dir: float) -> void:
|
||||||
if dir > 0.0 and root.scale.x < 0.0:
|
if dir > 0.0 and root.scale.x < 0.0:
|
||||||
root.scale.x = 1.0;
|
root.scale.x = 1.0;
|
||||||
|
@ -72,6 +75,7 @@ func summon_minion(p_position: Vector2) -> void:
|
||||||
minion.play_summoning_effect()
|
minion.play_summoning_effect()
|
||||||
|
|
||||||
|
|
||||||
|
## Method is used when this agent is summoned from the dungeons of the castle AaaAaaAAAAAaaAAaaaaaa
|
||||||
func play_summoning_effect() -> void:
|
func play_summoning_effect() -> void:
|
||||||
summoning_effect.emitting = true
|
summoning_effect.emitting = true
|
||||||
|
|
||||||
|
@ -86,6 +90,7 @@ func is_good_position(p_position: Vector2) -> bool:
|
||||||
return collision.is_empty()
|
return collision.is_empty()
|
||||||
|
|
||||||
|
|
||||||
|
## When agent is damaged...
|
||||||
func _damaged(_amount: float, knockback: Vector2) -> void:
|
func _damaged(_amount: float, knockback: Vector2) -> void:
|
||||||
apply_knockback(knockback)
|
apply_knockback(knockback)
|
||||||
animation_player.play(&"hurt")
|
animation_player.play(&"hurt")
|
||||||
|
@ -102,6 +107,7 @@ func _damaged(_amount: float, knockback: Vector2) -> void:
|
||||||
hsm.set_active(true)
|
hsm.set_active(true)
|
||||||
|
|
||||||
|
|
||||||
|
## Push agent in the knockback direction for the specified number of physics frames.
|
||||||
func apply_knockback(knockback: Vector2, frames: int = 10) -> void:
|
func apply_knockback(knockback: Vector2, frames: int = 10) -> void:
|
||||||
if knockback.is_zero_approx():
|
if knockback.is_zero_approx():
|
||||||
return
|
return
|
||||||
|
|
|
@ -12,10 +12,13 @@ class_name Health
|
||||||
extends Node
|
extends Node
|
||||||
## Tracks health and emits signal when damaged or dead.
|
## Tracks health and emits signal when damaged or dead.
|
||||||
|
|
||||||
|
## Emitted when health is reduced to 0.
|
||||||
signal death
|
signal death
|
||||||
|
|
||||||
|
## Emitted when health is damaged.
|
||||||
signal damaged(amount: float, knockback: Vector2)
|
signal damaged(amount: float, knockback: Vector2)
|
||||||
|
|
||||||
|
## Initial health value.
|
||||||
@export var max_health: float = 10.0
|
@export var max_health: float = 10.0
|
||||||
|
|
||||||
var _current: float
|
var _current: float
|
||||||
|
@ -38,5 +41,6 @@ func take_damage(amount: float, knockback: Vector2) -> void:
|
||||||
damaged.emit(amount, knockback)
|
damaged.emit(amount, knockback)
|
||||||
|
|
||||||
|
|
||||||
|
## Returns current health.
|
||||||
func get_current() -> float:
|
func get_current() -> float:
|
||||||
return _current
|
return _current
|
||||||
|
|
|
@ -12,10 +12,16 @@ class_name Hitbox
|
||||||
extends Area2D
|
extends Area2D
|
||||||
## Area that deals damage.
|
## Area that deals damage.
|
||||||
|
|
||||||
|
## Damage value to apply.
|
||||||
@export var damage: float = 1.0
|
@export var damage: float = 1.0
|
||||||
|
|
||||||
|
## Push back the victim.
|
||||||
@export var knockback_enabled: bool = false
|
@export var knockback_enabled: bool = false
|
||||||
|
|
||||||
|
## Desired pushback speed.
|
||||||
@export var knockback_strength: float = 500.0
|
@export var knockback_strength: float = 500.0
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
area_entered.connect(_area_entered)
|
area_entered.connect(_area_entered)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ class_name Hurtbox
|
||||||
extends Area2D
|
extends Area2D
|
||||||
## Area that registers damage.
|
## Area that registers damage.
|
||||||
|
|
||||||
|
|
||||||
@export var health: Health
|
@export var health: Health
|
||||||
|
|
||||||
var last_attack_vector: Vector2
|
var last_attack_vector: Vector2
|
||||||
|
|
|
@ -10,11 +10,17 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## Arrive to a position, with a bias to horizontal movement.
|
## ArrivePos: Arrive to a position, with a bias to horizontal movement.
|
||||||
|
## Returns SUCCESS when close to the target position (see tolerance);
|
||||||
|
## otherwise returns RUNNING.
|
||||||
|
|
||||||
|
## Blackboard variable that stores the target position (Vector2)
|
||||||
@export var target_position_var := "pos"
|
@export var target_position_var := "pos"
|
||||||
|
|
||||||
|
## Variable that stores desired speed (float)
|
||||||
@export var speed_var := "speed"
|
@export var speed_var := "speed"
|
||||||
|
|
||||||
|
## How close should the agent be to the target position to return SUCCESS.
|
||||||
@export var tolerance := 50.0
|
@export var tolerance := 50.0
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,10 +36,13 @@ func _tick(_delta: float) -> Status:
|
||||||
|
|
||||||
var speed: float = blackboard.get_var(speed_var, 10.0)
|
var speed: float = blackboard.get_var(speed_var, 10.0)
|
||||||
var dist: float = absf(agent.global_position.x - target_pos.x)
|
var dist: float = absf(agent.global_position.x - target_pos.x)
|
||||||
|
var dir: Vector2 = agent.global_position.direction_to(target_pos)
|
||||||
|
|
||||||
|
# Prefer horizontal movement:
|
||||||
var vertical_factor: float = remap(dist, 200.0, 500.0, 1.0, 0.0)
|
var vertical_factor: float = remap(dist, 200.0, 500.0, 1.0, 0.0)
|
||||||
vertical_factor = clampf(vertical_factor, 0.0, 1.0)
|
vertical_factor = clampf(vertical_factor, 0.0, 1.0)
|
||||||
var dir: Vector2 = agent.global_position.direction_to(target_pos)
|
|
||||||
dir.y *= vertical_factor
|
dir.y *= vertical_factor
|
||||||
|
|
||||||
var desired_velocity: Vector2 = dir.normalized() * speed
|
var desired_velocity: Vector2 = dir.normalized() * speed
|
||||||
agent.velocity = lerp(agent.velocity, desired_velocity, 0.2)
|
agent.velocity = lerp(agent.velocity, desired_velocity, 0.2)
|
||||||
agent.move_and_slide()
|
agent.move_and_slide()
|
||||||
|
|
|
@ -13,14 +13,19 @@ extends BTAction
|
||||||
## BackAway
|
## BackAway
|
||||||
## Returns RUNNING always.
|
## Returns RUNNING always.
|
||||||
|
|
||||||
|
## Blackboard variable that stores desired speed.
|
||||||
@export var speed_var: String = "speed"
|
@export var speed_var: String = "speed"
|
||||||
|
|
||||||
|
## How much can we deviate from the "away" direction (in radians).
|
||||||
@export var max_angle_deviation: float = 0.7
|
@export var max_angle_deviation: float = 0.7
|
||||||
|
|
||||||
var _dir: Vector2
|
var _dir: Vector2
|
||||||
var _desired_velocity: Vector2
|
var _desired_velocity: Vector2
|
||||||
|
|
||||||
|
|
||||||
# Called each time this task is entered.
|
# Called each time this task is entered.
|
||||||
func _enter() -> void:
|
func _enter() -> void:
|
||||||
|
# Determine "away" direction and desired velocity
|
||||||
_dir = Vector2.LEFT * agent.get_facing()
|
_dir = Vector2.LEFT * agent.get_facing()
|
||||||
var speed: float = blackboard.get_var(speed_var, 200.0)
|
var speed: float = blackboard.get_var(speed_var, 200.0)
|
||||||
var rand_angle = randf_range(-max_angle_deviation, max_angle_deviation)
|
var rand_angle = randf_range(-max_angle_deviation, max_angle_deviation)
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## FaceTarget
|
## FaceTarget and return SUCCESS.
|
||||||
|
## Returns FAILURE if target is not a valid Node2D instance.
|
||||||
|
|
||||||
|
## Blackboard variable that stores our target (expecting Node2D).
|
||||||
@export var target_var: String = "target"
|
@export var target_var: String = "target"
|
||||||
|
|
||||||
# Display a customized name (requires @tool).
|
# Display a customized name (requires @tool).
|
||||||
|
|
|
@ -10,10 +10,13 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
|
|
||||||
## Get first node in group and save it to the blackboard.
|
## Get first node in group and save it to the blackboard.
|
||||||
|
## Returns FAILURE if group contains 0 nodes.
|
||||||
|
|
||||||
|
## Name of the SceneTree group.
|
||||||
@export var group: StringName
|
@export var group: StringName
|
||||||
|
|
||||||
|
## Blackboard variable in which the task will store the acquired node.
|
||||||
@export var output_var: String = "target"
|
@export var output_var: String = "target"
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +27,8 @@ func _generate_name() -> String:
|
||||||
]
|
]
|
||||||
|
|
||||||
func _tick(_delta: float) -> Status:
|
func _tick(_delta: float) -> Status:
|
||||||
var node = agent.get_tree().get_first_node_in_group(group)
|
var nodes: Array[Node] = agent.get_tree().get_nodes_in_group(group)
|
||||||
blackboard.set_var(output_var, node)
|
if nodes.size() == 0:
|
||||||
|
return FAILURE
|
||||||
|
blackboard.set_var(output_var, nodes[0])
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
|
|
|
@ -16,8 +16,13 @@ extends BTCondition
|
||||||
## Returns SUCCESS if the agent is within the defined range;
|
## Returns SUCCESS if the agent is within the defined range;
|
||||||
## otherwise, returns FAILURE.
|
## otherwise, returns FAILURE.
|
||||||
|
|
||||||
|
## Minimum distance to target.
|
||||||
@export var distance_min: float
|
@export var distance_min: float
|
||||||
|
|
||||||
|
## Maximum distance to target.
|
||||||
@export var distance_max: float
|
@export var distance_max: float
|
||||||
|
|
||||||
|
## Blackboard variable that holds the target (expecting Node2D).
|
||||||
@export var target_var := "target"
|
@export var target_var := "target"
|
||||||
|
|
||||||
var _min_distance_squared: float
|
var _min_distance_squared: float
|
||||||
|
@ -26,24 +31,25 @@ var _max_distance_squared: float
|
||||||
|
|
||||||
# Called to generate a display name for the task.
|
# Called to generate a display name for the task.
|
||||||
func _generate_name() -> String:
|
func _generate_name() -> String:
|
||||||
return "InRange (%d, %d) of %s" % [distance_min, distance_max,
|
return "InRange (%d, %d) of %s" % [distance_min, distance_max,
|
||||||
LimboUtility.decorate_var(target_var)]
|
LimboUtility.decorate_var(target_var)]
|
||||||
|
|
||||||
|
|
||||||
# Called to initialize the task.
|
# Called to initialize the task.
|
||||||
func _setup() -> void:
|
func _setup() -> void:
|
||||||
_min_distance_squared = distance_min * distance_min
|
## Small performace optimization
|
||||||
_max_distance_squared = distance_max * distance_max
|
_min_distance_squared = distance_min * distance_min
|
||||||
|
_max_distance_squared = distance_max * distance_max
|
||||||
|
|
||||||
|
|
||||||
# Called when the task is executed.
|
# Called when the task is executed.
|
||||||
func _tick(_delta: float) -> Status:
|
func _tick(_delta: float) -> Status:
|
||||||
var target: Node2D = blackboard.get_var(target_var, null)
|
var target: Node2D = blackboard.get_var(target_var, null)
|
||||||
if not is_instance_valid(target):
|
if not is_instance_valid(target):
|
||||||
return FAILURE
|
return FAILURE
|
||||||
|
|
||||||
var dist_sq: float = agent.global_position.distance_squared_to(target.global_position)
|
var dist_sq: float = agent.global_position.distance_squared_to(target.global_position)
|
||||||
if dist_sq >= _min_distance_squared and dist_sq <= _max_distance_squared:
|
if dist_sq >= _min_distance_squared and dist_sq <= _max_distance_squared:
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
else:
|
else:
|
||||||
return FAILURE
|
return FAILURE
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#*
|
#*
|
||||||
#* leap_forward.gd
|
#* move_forward.gd
|
||||||
#* =============================================================================
|
#* =============================================================================
|
||||||
#* Copyright 2021-2024 Serhii Snitsaruk
|
#* Copyright 2021-2024 Serhii Snitsaruk
|
||||||
#*
|
#*
|
||||||
|
@ -10,22 +10,27 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## LeapForward: Applies force each tick until duration is exceeded.
|
## MoveForward: Applies velocity each tick until duration is exceeded.
|
||||||
## Returns SUCCESS if elapsed time exceeded duration.
|
## Returns SUCCESS if elapsed time exceeded duration.
|
||||||
## Returns RUNNING if elapsed time didn't exceed duration.
|
## Returns RUNNING if elapsed time didn't exceed duration.
|
||||||
|
|
||||||
|
## Blackboard variable that stores desired speed.
|
||||||
|
@export var speed_var: String = "speed"
|
||||||
|
|
||||||
@export var force: float = 1000.0
|
## How long to perform this task (in seconds).
|
||||||
@export var duration: float = 0.1
|
@export var duration: float = 0.1
|
||||||
|
|
||||||
# Display a customized name (requires @tool).
|
# Display a customized name (requires @tool).
|
||||||
func _generate_name() -> String:
|
func _generate_name() -> String:
|
||||||
return "LeapForward force: " + str(force)
|
return "MoveForward speed: %s duration: %ss" % [
|
||||||
|
LimboUtility.decorate_var(speed_var),
|
||||||
|
duration]
|
||||||
|
|
||||||
# Called each time this task is ticked (aka executed).
|
# Called each time this task is ticked (aka executed).
|
||||||
func _tick(_delta: float) -> Status:
|
func _tick(_delta: float) -> Status:
|
||||||
var facing: float = agent.get_facing()
|
var facing: float = agent.get_facing()
|
||||||
var desired_velocity: Vector2 = Vector2.RIGHT * facing * force
|
var speed: float = blackboard.get_var(speed_var, 100.0)
|
||||||
|
var desired_velocity: Vector2 = Vector2.RIGHT * facing * speed
|
||||||
agent.velocity = lerp(agent.velocity, desired_velocity, 0.2)
|
agent.velocity = lerp(agent.velocity, desired_velocity, 0.2)
|
||||||
agent.move_and_slide()
|
agent.move_and_slide()
|
||||||
agent.update_facing()
|
agent.update_facing()
|
|
@ -16,24 +16,32 @@ extends BTAction
|
||||||
## Returns SUCCESS, when at the desired position from target (flanking it).
|
## Returns SUCCESS, when at the desired position from target (flanking it).
|
||||||
## Returns FAILURE, if target is not a valid Node2D instance.
|
## Returns FAILURE, if target is not a valid Node2D instance.
|
||||||
|
|
||||||
|
## How close should the agent be to the desired position to return SUCCESS.
|
||||||
const TOLERANCE := 30.0
|
const TOLERANCE := 30.0
|
||||||
|
|
||||||
|
## Blackboard variable that stores our target (expecting Node2D).
|
||||||
@export var target_var: String = "target"
|
@export var target_var: String = "target"
|
||||||
|
|
||||||
|
## Blackboard variable that stores desired speed.
|
||||||
@export var speed_var: String = "speed"
|
@export var speed_var: String = "speed"
|
||||||
|
|
||||||
|
## Desired distance from target.
|
||||||
@export var approach_distance: float = 100.0
|
@export var approach_distance: float = 100.0
|
||||||
|
|
||||||
#var _side: float
|
|
||||||
var _waypoint: Vector2
|
var _waypoint: Vector2
|
||||||
|
|
||||||
|
|
||||||
# Display a customized name (requires @tool).
|
# Display a customized name (requires @tool).
|
||||||
func _generate_name() -> String:
|
func _generate_name() -> String:
|
||||||
return "Pursue %s" % [LimboUtility.decorate_var(target_var)]
|
return "Pursue %s" % [LimboUtility.decorate_var(target_var)]
|
||||||
|
|
||||||
|
|
||||||
|
# Called each time this task is entered.
|
||||||
func _enter() -> void:
|
func _enter() -> void:
|
||||||
var target: Node2D = blackboard.get_var(target_var, null)
|
var target: Node2D = blackboard.get_var(target_var, null)
|
||||||
if is_instance_valid(target):
|
if is_instance_valid(target):
|
||||||
|
# Movement is performed in smaller steps.
|
||||||
|
# For each step, we select a new waypoint.
|
||||||
_select_new_waypoint(_get_desired_position(target))
|
_select_new_waypoint(_get_desired_position(target))
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,9 +55,10 @@ func _tick(_delta: float) -> Status:
|
||||||
if agent.global_position.distance_to(desired_pos) < TOLERANCE:
|
if agent.global_position.distance_to(desired_pos) < TOLERANCE:
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
|
|
||||||
var speed: float = blackboard.get_var(speed_var, 200.0)
|
|
||||||
if agent.global_position.distance_to(_waypoint) < TOLERANCE:
|
if agent.global_position.distance_to(_waypoint) < TOLERANCE:
|
||||||
_select_new_waypoint(desired_pos)
|
_select_new_waypoint(desired_pos)
|
||||||
|
|
||||||
|
var speed: float = blackboard.get_var(speed_var, 200.0)
|
||||||
var desired_velocity: Vector2 = agent.global_position.direction_to(_waypoint) * speed
|
var desired_velocity: Vector2 = agent.global_position.direction_to(_waypoint) * speed
|
||||||
agent.velocity = lerp(agent.velocity, desired_velocity, 0.2)
|
agent.velocity = lerp(agent.velocity, desired_velocity, 0.2)
|
||||||
agent.move_and_slide()
|
agent.move_and_slide()
|
||||||
|
@ -57,7 +66,7 @@ func _tick(_delta: float) -> Status:
|
||||||
return RUNNING
|
return RUNNING
|
||||||
|
|
||||||
|
|
||||||
## Get closest flanking position to target.
|
## Get the closest flanking position to target.
|
||||||
func _get_desired_position(target: Node2D) -> Vector2:
|
func _get_desired_position(target: Node2D) -> Vector2:
|
||||||
var side: float = signf(agent.global_position.x - target.global_position.x)
|
var side: float = signf(agent.global_position.x - target.global_position.x)
|
||||||
var desired_pos: Vector2 = target.global_position
|
var desired_pos: Vector2 = target.global_position
|
||||||
|
|
|
@ -23,9 +23,7 @@ enum AgentSide {
|
||||||
## Blackboard variable that holds current target (should be a Node2D instance).
|
## Blackboard variable that holds current target (should be a Node2D instance).
|
||||||
@export var target_var: String = "target"
|
@export var target_var: String = "target"
|
||||||
|
|
||||||
## Should closest side be selected?
|
## Which agent's side should we flank?
|
||||||
@export var closest_side: bool = false
|
|
||||||
|
|
||||||
@export var flank_side: AgentSide = AgentSide.CLOSEST
|
@export var flank_side: AgentSide = AgentSide.CLOSEST
|
||||||
|
|
||||||
## Minimum range relative to the target.
|
## Minimum range relative to the target.
|
||||||
|
@ -37,6 +35,7 @@ enum AgentSide {
|
||||||
## Blackboard variable that will be used to store selected position.
|
## Blackboard variable that will be used to store selected position.
|
||||||
@export var position_var: String = "pos"
|
@export var position_var: String = "pos"
|
||||||
|
|
||||||
|
|
||||||
# Display a customized name (requires @tool).
|
# Display a customized name (requires @tool).
|
||||||
func _generate_name() -> String:
|
func _generate_name() -> String:
|
||||||
return "SelectFlankingPos target: %s range: [%s, %s] side: %s ➜%s" % [
|
return "SelectFlankingPos target: %s range: [%s, %s] side: %s ➜%s" % [
|
||||||
|
@ -46,17 +45,18 @@ func _generate_name() -> String:
|
||||||
AgentSide.keys()[flank_side],
|
AgentSide.keys()[flank_side],
|
||||||
LimboUtility.decorate_var(position_var)]
|
LimboUtility.decorate_var(position_var)]
|
||||||
|
|
||||||
|
|
||||||
# Called each time this task is ticked (aka executed).
|
# Called each time this task is ticked (aka executed).
|
||||||
func _tick(_delta: float) -> Status:
|
func _tick(_delta: float) -> Status:
|
||||||
var target := blackboard.get_var(target_var) as Node2D
|
var target := blackboard.get_var(target_var) as Node2D
|
||||||
if not is_instance_valid(target):
|
if not is_instance_valid(target):
|
||||||
return FAILURE
|
return FAILURE
|
||||||
|
|
||||||
var dir: float
|
var dir: float # 1.0 is right, -1.0 is left (relative to target)
|
||||||
match flank_side:
|
match flank_side:
|
||||||
AgentSide.FARTHEST:
|
AgentSide.FARTHEST:
|
||||||
dir = signf(target.global_position.x - agent.global_position.x)
|
dir = signf(target.global_position.x - agent.global_position.x)
|
||||||
AgentSide.CLOSEST:
|
AgentSide.CLOSEST :
|
||||||
dir = -signf(target.global_position.x - agent.global_position.x)
|
dir = -signf(target.global_position.x - agent.global_position.x)
|
||||||
AgentSide.BACK:
|
AgentSide.BACK:
|
||||||
dir = -target.get_facing()
|
dir = -target.get_facing()
|
||||||
|
|
|
@ -3,23 +3,29 @@ extends BTAction
|
||||||
## SelectRandomNearbyPos: Select a position nearby within specified range.
|
## SelectRandomNearbyPos: Select a position nearby within specified range.
|
||||||
## Returns SUCCESS.
|
## Returns SUCCESS.
|
||||||
|
|
||||||
## Maximum distance to the desired position.
|
## Minimum distance to the desired position.
|
||||||
@export var range_min: float = 300.0
|
@export var range_min: float = 300.0
|
||||||
|
|
||||||
|
## Maximum distance to the desired position.
|
||||||
@export var range_max: float = 500.0
|
@export var range_max: float = 500.0
|
||||||
|
|
||||||
|
## Blackboard variable that will be used to store the desired position.
|
||||||
@export var position_var: String = "pos"
|
@export var position_var: String = "pos"
|
||||||
|
|
||||||
|
|
||||||
# Display a customized name (requires @tool).
|
# Display a customized name (requires @tool).
|
||||||
func _generate_name() -> String:
|
func _generate_name() -> String:
|
||||||
return "SelectRandomNearbyPos range: [%s, %s] ➜%s" % [
|
return "SelectRandomNearbyPos range: [%s, %s] ➜%s" % [
|
||||||
range_min, range_max,
|
range_min, range_max,
|
||||||
LimboUtility.decorate_var(position_var)]
|
LimboUtility.decorate_var(position_var)]
|
||||||
|
|
||||||
|
|
||||||
# Called each time this task is ticked (aka executed).
|
# Called each time this task is ticked (aka executed).
|
||||||
func _tick(_delta: float) -> Status:
|
func _tick(_delta: float) -> Status:
|
||||||
var pos: Vector2
|
var pos: Vector2
|
||||||
var is_good_position: bool = false
|
var is_good_position: bool = false
|
||||||
while not is_good_position:
|
while not is_good_position:
|
||||||
# Randomize until we find a good position (in other words, not outside the arena)
|
# Randomize until we find a good position (good position == not outside the arena).
|
||||||
var angle: float = randf() * TAU
|
var angle: float = randf() * TAU
|
||||||
var rand_distance: float = randf_range(range_min, range_max)
|
var rand_distance: float = randf_range(range_min, range_max)
|
||||||
pos = agent.global_position + Vector2(sin(angle), cos(angle)) * rand_distance
|
pos = agent.global_position + Vector2(sin(angle), cos(angle)) * rand_distance
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/select_flanking_pos.gd" id="2_t3udh"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/select_flanking_pos.gd" id="2_t3udh"]
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_u2ra5"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_u2ra5"]
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/face_target.gd" id="4_xwjl7"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/face_target.gd" id="4_xwjl7"]
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/leap_forward.gd" id="5_f6dg8"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/move_forward.gd" id="5_ucvak"]
|
||||||
|
|
||||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_qd806"]
|
[sub_resource type="BlackboardPlan" id="BlackboardPlan_qd806"]
|
||||||
var/speed/name = "speed"
|
var/speed/name = "speed"
|
||||||
|
@ -14,7 +14,7 @@ var/speed/hint = 1
|
||||||
var/speed/hint_string = "10,1000,10"
|
var/speed/hint_string = "10,1000,10"
|
||||||
var/charge_speed/name = "charge_speed"
|
var/charge_speed/name = "charge_speed"
|
||||||
var/charge_speed/type = 3
|
var/charge_speed/type = 3
|
||||||
var/charge_speed/value = 800.0
|
var/charge_speed/value = 1000.0
|
||||||
var/charge_speed/hint = 1
|
var/charge_speed/hint = 1
|
||||||
var/charge_speed/hint_string = "10,1000,10"
|
var/charge_speed/hint_string = "10,1000,10"
|
||||||
|
|
||||||
|
@ -43,7 +43,6 @@ output_var = "target"
|
||||||
[sub_resource type="BTAction" id="BTAction_pmvd0"]
|
[sub_resource type="BTAction" id="BTAction_pmvd0"]
|
||||||
script = ExtResource("2_t3udh")
|
script = ExtResource("2_t3udh")
|
||||||
target_var = "target"
|
target_var = "target"
|
||||||
closest_side = false
|
|
||||||
flank_side = 0
|
flank_side = 0
|
||||||
range_min = 500
|
range_min = 500
|
||||||
range_max = 600
|
range_max = 600
|
||||||
|
@ -98,8 +97,8 @@ animation_name = &"charge"
|
||||||
blend = 0.05
|
blend = 0.05
|
||||||
|
|
||||||
[sub_resource type="BTAction" id="BTAction_o18uk"]
|
[sub_resource type="BTAction" id="BTAction_o18uk"]
|
||||||
script = ExtResource("5_f6dg8")
|
script = ExtResource("5_ucvak")
|
||||||
force = 1000.0
|
speed_var = "charge_speed"
|
||||||
duration = 2.0
|
duration = 2.0
|
||||||
|
|
||||||
[sub_resource type="BTSequence" id="BTSequence_8lur1"]
|
[sub_resource type="BTSequence" id="BTSequence_8lur1"]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/select_flanking_pos.gd" id="2_5nwkp"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/select_flanking_pos.gd" id="2_5nwkp"]
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_3tom2"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="3_3tom2"]
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/face_target.gd" id="4_hi228"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/face_target.gd" id="4_hi228"]
|
||||||
[ext_resource type="Script" path="res://demo/ai/tasks/leap_forward.gd" id="5_fpbac"]
|
[ext_resource type="Script" path="res://demo/ai/tasks/move_forward.gd" id="5_au5yc"]
|
||||||
|
|
||||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_46tbn"]
|
[sub_resource type="BlackboardPlan" id="BlackboardPlan_46tbn"]
|
||||||
var/speed/name = "speed"
|
var/speed/name = "speed"
|
||||||
|
@ -12,6 +12,11 @@ var/speed/type = 3
|
||||||
var/speed/value = 400.0
|
var/speed/value = 400.0
|
||||||
var/speed/hint = 1
|
var/speed/hint = 1
|
||||||
var/speed/hint_string = "10,1000,10"
|
var/speed/hint_string = "10,1000,10"
|
||||||
|
var/charge_speed/name = "charge_speed"
|
||||||
|
var/charge_speed/type = 3
|
||||||
|
var/charge_speed/value = 1000.0
|
||||||
|
var/charge_speed/hint = 0
|
||||||
|
var/charge_speed/hint_string = ""
|
||||||
|
|
||||||
[sub_resource type="BBNode" id="BBNode_nrd4b"]
|
[sub_resource type="BBNode" id="BBNode_nrd4b"]
|
||||||
saved_value = NodePath("AnimationPlayer")
|
saved_value = NodePath("AnimationPlayer")
|
||||||
|
@ -38,7 +43,6 @@ children = [SubResource("BTPlayAnimation_qiw21"), SubResource("BTRandomWait_xlud
|
||||||
[sub_resource type="BTAction" id="BTAction_85keo"]
|
[sub_resource type="BTAction" id="BTAction_85keo"]
|
||||||
script = ExtResource("2_5nwkp")
|
script = ExtResource("2_5nwkp")
|
||||||
target_var = "target"
|
target_var = "target"
|
||||||
closest_side = true
|
|
||||||
flank_side = 0
|
flank_side = 0
|
||||||
range_min = 300
|
range_min = 300
|
||||||
range_max = 400
|
range_max = 400
|
||||||
|
@ -83,8 +87,8 @@ animation_player = SubResource("BBNode_s8evu")
|
||||||
animation_name = &"attack_1"
|
animation_name = &"attack_1"
|
||||||
|
|
||||||
[sub_resource type="BTAction" id="BTAction_u22bc"]
|
[sub_resource type="BTAction" id="BTAction_u22bc"]
|
||||||
script = ExtResource("5_fpbac")
|
script = ExtResource("5_au5yc")
|
||||||
force = 1000.0
|
speed_var = "charge_speed"
|
||||||
duration = 0.1
|
duration = 0.1
|
||||||
|
|
||||||
[sub_resource type="BTParallel" id="BTParallel_ec2e3"]
|
[sub_resource type="BTParallel" id="BTParallel_ec2e3"]
|
||||||
|
@ -104,8 +108,8 @@ animation_player = SubResource("BBNode_3oljv")
|
||||||
animation_name = &"attack_2"
|
animation_name = &"attack_2"
|
||||||
|
|
||||||
[sub_resource type="BTAction" id="BTAction_yuxl3"]
|
[sub_resource type="BTAction" id="BTAction_yuxl3"]
|
||||||
script = ExtResource("5_fpbac")
|
script = ExtResource("5_au5yc")
|
||||||
force = 1000.0
|
speed_var = "charge_speed"
|
||||||
duration = 0.1
|
duration = 0.1
|
||||||
|
|
||||||
[sub_resource type="BTParallel" id="BTParallel_thojy"]
|
[sub_resource type="BTParallel" id="BTParallel_thojy"]
|
||||||
|
@ -125,8 +129,8 @@ animation_player = SubResource("BBNode_ot40l")
|
||||||
animation_name = &"attack_3"
|
animation_name = &"attack_3"
|
||||||
|
|
||||||
[sub_resource type="BTAction" id="BTAction_rwp18"]
|
[sub_resource type="BTAction" id="BTAction_rwp18"]
|
||||||
script = ExtResource("5_fpbac")
|
script = ExtResource("5_au5yc")
|
||||||
force = 1000.0
|
speed_var = "charge_speed"
|
||||||
duration = 0.1
|
duration = 0.1
|
||||||
|
|
||||||
[sub_resource type="BTParallel" id="BTParallel_qmdfb"]
|
[sub_resource type="BTParallel" id="BTParallel_qmdfb"]
|
||||||
|
|
Binary file not shown.
|
@ -4,10 +4,12 @@ extends CharacterBody2D
|
||||||
@onready var hurtbox: Hurtbox = $Hurtbox
|
@onready var hurtbox: Hurtbox = $Hurtbox
|
||||||
@onready var root: Node2D = $Root
|
@onready var root: Node2D = $Root
|
||||||
|
|
||||||
|
|
||||||
func _on_health_damaged(_amount: float, _knockback: Vector2) -> void:
|
func _on_health_damaged(_amount: float, _knockback: Vector2) -> void:
|
||||||
root.scale.x = -signf(hurtbox.last_attack_vector.x)
|
root.scale.x = -signf(hurtbox.last_attack_vector.x)
|
||||||
animation_player.clear_queue()
|
animation_player.clear_queue()
|
||||||
animation_player.play(&"hurt", 0.1)
|
animation_player.play(&"hurt", 0.1)
|
||||||
|
|
||||||
|
|
||||||
func get_facing() -> float:
|
func get_facing() -> float:
|
||||||
return signf(root.scale.x)
|
return signf(root.scale.x)
|
||||||
|
|
|
@ -77,4 +77,4 @@ func _on_agent_selection_id_pressed(id: int) -> void:
|
||||||
_load_agent("res://demo/agents/".path_join(agent_files[id]))
|
_load_agent("res://demo/agents/".path_join(agent_files[id]))
|
||||||
agent_selection.text = bt_player.behavior_tree.resource_path.get_file()
|
agent_selection.text = bt_player.behavior_tree.resource_path.get_file()
|
||||||
previous.disabled = id == 0
|
previous.disabled = id == 0
|
||||||
next.disabled = id == 8
|
next.disabled = id == (agent_files.size()-1)
|
||||||
|
|
Loading…
Reference in New Issue