Added wander and look around behaviours.
parent
bec51332c7
commit
3ce12e24be
|
@ -0,0 +1 @@
|
|||
{"included":{"res://tests/scenes/game_tests.gd":["test_save_game"]},"server_port":31002,"skipped":{},"version":"1.0"}
|
|
@ -0,0 +1,37 @@
|
|||
extends BTAction
|
||||
|
||||
@export var radius:float = 1.0
|
||||
|
||||
@export var output_var: StringName = &"target_location"
|
||||
@export var navigatable_target:bool = false
|
||||
@export var stay_in_radius:bool = true
|
||||
|
||||
var _reference_location:Vector3 = Vector3.INF
|
||||
|
||||
func _setup() -> void:
|
||||
_reference_location = agent.global_position
|
||||
|
||||
func _tick(_delta: float) -> Status:
|
||||
assert(_reference_location != Vector3.INF)
|
||||
|
||||
var target_is_navigatable = true
|
||||
var random_location:Vector3 = Vector3.ZERO
|
||||
|
||||
var agent_npc:NonPlayerCharacter = agent as NonPlayerCharacter
|
||||
if navigatable_target:
|
||||
assert(agent_npc)
|
||||
target_is_navigatable = false
|
||||
|
||||
if not stay_in_radius:
|
||||
_reference_location = agent_npc.global_position
|
||||
|
||||
var random_angle:float = randf_range(-PI, PI)
|
||||
random_location = _reference_location + radius * Vector3(cos(random_angle), 0, sin(random_angle))
|
||||
if navigatable_target and agent_npc.is_target_navigatable(random_location):
|
||||
target_is_navigatable = true
|
||||
|
||||
if target_is_navigatable:
|
||||
blackboard.set_var(output_var, random_location)
|
||||
return SUCCESS
|
||||
|
||||
return FAILURE
|
|
@ -0,0 +1,42 @@
|
|||
@tool
|
||||
extends BTAction
|
||||
|
||||
@export var target_location_var: StringName = &"target_location"
|
||||
|
||||
var target_position: Vector3 = Vector3.ZERO
|
||||
|
||||
var _current_look_direction:Vector3 = Vector3.BACK
|
||||
var _current_look_angle:float = 0
|
||||
var _target_look_direction:Vector3 = Vector3.BACK
|
||||
var _target_look_angle:float = 0
|
||||
var _look_angle_damper:SpringDamper = SpringDamper.new(0, 2, 0.06, 0.003)
|
||||
|
||||
func _generate_name() -> String:
|
||||
return "Look at Target " + LimboUtility.decorate_var(target_location_var)
|
||||
|
||||
func _tick(delta: float) -> Status:
|
||||
target_position = blackboard.get_var(target_location_var)
|
||||
|
||||
update_look_direction(delta)
|
||||
|
||||
if absf(_target_look_angle - _current_look_angle) < deg_to_rad(5):
|
||||
return SUCCESS
|
||||
|
||||
return RUNNING
|
||||
|
||||
func update_look_direction(delta:float) -> void:
|
||||
_target_look_direction = (target_position - agent.global_position).normalized()
|
||||
_current_look_direction = agent.basis.z
|
||||
|
||||
_current_look_angle = _current_look_direction.signed_angle_to(Vector3.BACK, Vector3.UP)
|
||||
_target_look_angle = _target_look_direction.signed_angle_to(Vector3.BACK, Vector3.UP)
|
||||
|
||||
if _target_look_angle - _current_look_angle > PI:
|
||||
_current_look_angle = _current_look_angle + PI * 2
|
||||
elif _current_look_angle - _target_look_angle > PI:
|
||||
_current_look_angle = _current_look_angle - PI * 2
|
||||
|
||||
var damped_look_angle:float = _look_angle_damper.calc(_current_look_angle, _target_look_angle, delta)
|
||||
|
||||
_current_look_direction = Vector3(sin(-damped_look_angle), 0, cos(-damped_look_angle))
|
||||
agent.basis = Basis.looking_at(-_current_look_direction)
|
|
@ -23,7 +23,7 @@ func _tick(delta: float) -> Status:
|
|||
update_look_direction(delta)
|
||||
|
||||
if absf(_target_look_angle - _current_look_angle) < deg_to_rad(5):
|
||||
return SUCCESS
|
||||
return RUNNING
|
||||
|
||||
return FAILURE
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
@tool
|
||||
extends BTAction
|
||||
|
||||
@export var target_var: StringName = &"target"
|
||||
var target_node:Node3D = null
|
||||
var current_target_name:String = ""
|
||||
|
||||
func _generate_name() -> String:
|
||||
return "NavigateTo \"%s\"" % [
|
||||
LimboUtility.decorate_var(target_var)
|
||||
]
|
||||
|
||||
func _tick(_delta: float) -> Status:
|
||||
target_node = blackboard.get_var(target_var)
|
||||
|
||||
if not is_instance_valid(target_node):
|
||||
return FAILURE
|
||||
|
||||
if current_target_name != target_node.name:
|
||||
current_target_name = target_node.name
|
||||
print ("Next target: " + current_target_name)
|
||||
|
||||
var agent_npc:NonPlayerCharacter = agent as NonPlayerCharacter
|
||||
if agent_npc:
|
||||
agent_npc.navigate_to(target_node.global_position)
|
||||
|
||||
var agent_node:Node3D = agent as Node3D
|
||||
if agent_node:
|
||||
var distance_to_target:float = (agent.global_position - target_node.global_position).length()
|
||||
if distance_to_target < 0.1:
|
||||
return SUCCESS
|
||||
|
||||
return RUNNING
|
|
@ -0,0 +1,25 @@
|
|||
@tool
|
||||
extends BTAction
|
||||
|
||||
@export var target_var: StringName = &"target_location"
|
||||
var target_location:Vector3 = Vector3.ZERO
|
||||
|
||||
func _generate_name() -> String:
|
||||
return "NavigateTo \"%s\"" % [
|
||||
LimboUtility.decorate_var(target_var)
|
||||
]
|
||||
|
||||
func _tick(_delta: float) -> Status:
|
||||
target_location = blackboard.get_var(target_var)
|
||||
|
||||
var agent_npc:NonPlayerCharacter = agent as NonPlayerCharacter
|
||||
if agent_npc:
|
||||
agent_npc.navigate_to(target_location)
|
||||
|
||||
var agent_node:Node3D = agent as Node3D
|
||||
if agent_node:
|
||||
var distance_to_target:float = (agent_node.global_position - target_location).length()
|
||||
if distance_to_target < 0.1:
|
||||
return SUCCESS
|
||||
|
||||
return RUNNING
|
|
@ -0,0 +1,9 @@
|
|||
[gd_resource type="BehaviorTree" load_steps=3 format=3 uid="uid://dck7kl4210076"]
|
||||
|
||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_dsl36"]
|
||||
|
||||
[sub_resource type="BTAlwaysSucceed" id="BTAlwaysSucceed_c7j70"]
|
||||
|
||||
[resource]
|
||||
blackboard_plan = SubResource("BlackboardPlan_dsl36")
|
||||
root_task = SubResource("BTAlwaysSucceed_c7j70")
|
|
@ -0,0 +1,31 @@
|
|||
[gd_resource type="BehaviorTree" load_steps=9 format=3 uid="uid://2v14hwp2gtg"]
|
||||
|
||||
[ext_resource type="Script" path="res://ai/tasks/look_at_location.gd" id="1_1lumv"]
|
||||
[ext_resource type="Script" path="res://ai/tasks/find_nearby_random_location.gd" id="2_jrbpg"]
|
||||
|
||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_sdda8"]
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_ba1hn"]
|
||||
script = ExtResource("2_jrbpg")
|
||||
radius = 1.0
|
||||
output_var = &"target_location"
|
||||
navigatable_target = true
|
||||
stay_in_radius = true
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_d7u7l"]
|
||||
script = ExtResource("1_1lumv")
|
||||
target_location_var = &"target_location"
|
||||
|
||||
[sub_resource type="BTWait" id="BTWait_jmtj2"]
|
||||
duration = 2.0
|
||||
|
||||
[sub_resource type="BTSequence" id="BTSequence_ouv1e"]
|
||||
children = [SubResource("BTAction_ba1hn"), SubResource("BTAction_d7u7l"), SubResource("BTWait_jmtj2")]
|
||||
|
||||
[sub_resource type="BTRepeat" id="BTRepeat_nqqvt"]
|
||||
forever = true
|
||||
children = [SubResource("BTSequence_ouv1e")]
|
||||
|
||||
[resource]
|
||||
blackboard_plan = SubResource("BlackboardPlan_sdda8")
|
||||
root_task = SubResource("BTRepeat_nqqvt")
|
|
@ -1,7 +1,7 @@
|
|||
[gd_resource type="BehaviorTree" load_steps=13 format=3 uid="uid://blccr23qjixws"]
|
||||
[gd_resource type="BehaviorTree" load_steps=12 format=3 uid="uid://blccr23qjixws"]
|
||||
|
||||
[ext_resource type="Script" path="res://ai/tasks/find_target_by_name.gd" id="1_v4edy"]
|
||||
[ext_resource type="Script" path="res://ai/tasks/look_at_target.gd" id="2_5373l"]
|
||||
[ext_resource type="Script" path="res://ai/tasks/navigate_to_location.gd" id="2_k36i0"]
|
||||
|
||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_yg732"]
|
||||
|
||||
|
@ -11,25 +11,23 @@ target_name = "Player"
|
|||
output_var = &"target"
|
||||
|
||||
[sub_resource type="BTWait" id="BTWait_8cgex"]
|
||||
duration = 2.0
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_xlccj"]
|
||||
[sub_resource type="BTAction" id="BTAction_qfrs5"]
|
||||
script = ExtResource("1_v4edy")
|
||||
target_name = "Bone"
|
||||
output_var = &"target"
|
||||
|
||||
[sub_resource type="BTWait" id="BTWait_8uvw7"]
|
||||
duration = 3.0
|
||||
|
||||
[sub_resource type="BTSequence" id="BTSequence_u84lc"]
|
||||
children = [SubResource("BTAction_7a1kv"), SubResource("BTWait_8cgex"), SubResource("BTAction_xlccj"), SubResource("BTWait_8uvw7")]
|
||||
children = [SubResource("BTAction_7a1kv"), SubResource("BTWait_8cgex"), SubResource("BTAction_qfrs5")]
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_jhwy8"]
|
||||
script = ExtResource("2_5373l")
|
||||
[sub_resource type="BTAction" id="BTAction_l2eti"]
|
||||
script = ExtResource("2_k36i0")
|
||||
target_var = &"target"
|
||||
|
||||
[sub_resource type="BTRepeat" id="BTRepeat_dam0f"]
|
||||
forever = true
|
||||
children = [SubResource("BTAction_jhwy8")]
|
||||
children = [SubResource("BTAction_l2eti")]
|
||||
|
||||
[sub_resource type="BTParallel" id="BTParallel_l5msj"]
|
||||
children = [SubResource("BTSequence_u84lc"), SubResource("BTRepeat_dam0f")]
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
[gd_resource type="BehaviorTree" load_steps=11 format=3 uid="uid://caxmpcyhpt6em"]
|
||||
|
||||
[ext_resource type="Script" path="res://ai/tasks/find_nearby_random_location.gd" id="1_5wpmm"]
|
||||
[ext_resource type="Script" path="res://ai/tasks/look_at_location.gd" id="2_d6sgo"]
|
||||
[ext_resource type="Script" path="res://ai/tasks/navigate_to_location.gd" id="3_ch0o3"]
|
||||
|
||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_yo8p7"]
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_s4a8v"]
|
||||
script = ExtResource("1_5wpmm")
|
||||
radius = 1.0
|
||||
output_var = &"target_location"
|
||||
navigatable_target = true
|
||||
stay_in_radius = true
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_lschq"]
|
||||
script = ExtResource("2_d6sgo")
|
||||
target_location_var = &"target_location"
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_onf00"]
|
||||
script = ExtResource("3_ch0o3")
|
||||
target_var = &"target_location"
|
||||
|
||||
[sub_resource type="BTWait" id="BTWait_yneys"]
|
||||
duration = 3.0
|
||||
|
||||
[sub_resource type="BTSequence" id="BTSequence_o4qno"]
|
||||
children = [SubResource("BTAction_s4a8v"), SubResource("BTAction_lschq"), SubResource("BTAction_onf00"), SubResource("BTWait_yneys")]
|
||||
|
||||
[sub_resource type="BTRepeat" id="BTRepeat_o23de"]
|
||||
forever = true
|
||||
children = [SubResource("BTSequence_o4qno")]
|
||||
|
||||
[resource]
|
||||
blackboard_plan = SubResource("BlackboardPlan_yo8p7")
|
||||
root_task = SubResource("BTRepeat_o23de")
|
|
@ -7,16 +7,30 @@ extends CharacterBody3D
|
|||
get:
|
||||
return reacts_to_player
|
||||
|
||||
@export var behaviour:BehaviorTree = null:
|
||||
set (value):
|
||||
behaviour = value
|
||||
if is_instance_valid(bt_player):
|
||||
bt_player.behavior_tree = behaviour
|
||||
get:
|
||||
return behaviour
|
||||
|
||||
@onready var geometry: Node3D = null
|
||||
@onready var player_detection: Area3D = %PlayerDetection
|
||||
@onready var default_geometry: Node3D = %DefaultGeometry
|
||||
@onready var animation_player: AnimationPlayer = %AnimationPlayer
|
||||
@onready var navigation_agent: NavigationAgent3D = %NavigationAgent
|
||||
@onready var bt_player: BTPlayer = %BTPlayer
|
||||
|
||||
const SPEED = 5.0
|
||||
const JUMP_VELOCITY = 4.5
|
||||
|
||||
var tool_damage:bool = false
|
||||
var tracking_node:Node3D = null
|
||||
var navigation_active:bool = false
|
||||
|
||||
var navigation_query_parameters:NavigationPathQueryParameters3D = NavigationPathQueryParameters3D.new()
|
||||
var navigation_query_result:NavigationPathQueryResult3D = NavigationPathQueryResult3D.new()
|
||||
|
||||
func _set_reacts_to_player(value:bool) -> bool:
|
||||
if player_detection != null:
|
||||
|
@ -33,6 +47,25 @@ func _ready() -> void:
|
|||
default_geometry.visible = false
|
||||
animation_player.set_root("Geometry")
|
||||
|
||||
if is_instance_valid(bt_player):
|
||||
bt_player.behavior_tree = behaviour
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
if navigation_active:
|
||||
var next_position:Vector3 = navigation_agent.get_next_path_position()
|
||||
|
||||
print("distance to target: %s" % navigation_agent.distance_to_target())
|
||||
|
||||
if navigation_agent.is_target_reached():
|
||||
print ("Target reached. Distance: %s" % navigation_agent.distance_to_target())
|
||||
navigation_active = false
|
||||
else:
|
||||
var direction = (next_position - global_position).normalized()
|
||||
basis = Basis.looking_at(-direction)
|
||||
|
||||
velocity = direction * 2
|
||||
move_and_slide()
|
||||
|
||||
func _on_player_detection_body_entered(body: Node3D) -> void:
|
||||
if body is Player:
|
||||
tracking_node = body
|
||||
|
@ -40,3 +73,25 @@ func _on_player_detection_body_entered(body: Node3D) -> void:
|
|||
func _on_player_detection_body_exited(body: Node3D) -> void:
|
||||
if body == tracking_node:
|
||||
tracking_node = null
|
||||
|
||||
func is_target_navigatable(target_position: Vector3) -> bool:
|
||||
navigation_query_parameters.map = get_world_3d().navigation_map
|
||||
navigation_query_parameters.start_position = global_position
|
||||
navigation_query_parameters.target_position = target_position
|
||||
navigation_query_parameters.navigation_layers = navigation_agent.navigation_layers
|
||||
|
||||
if NavigationServer3D.map_get_iteration_id(navigation_query_parameters.map) == 0:
|
||||
return false
|
||||
|
||||
NavigationServer3D.query_path(navigation_query_parameters, navigation_query_result)
|
||||
var query_path: PackedVector3Array = navigation_query_result.path
|
||||
|
||||
if query_path.size() > 0 and (query_path[query_path.size() - 1] - target_position).length() <= navigation_agent.target_desired_distance:
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
func navigate_to(target_position: Vector3) -> void:
|
||||
navigation_agent.target_position = target_position
|
||||
assert (is_target_navigatable(target_position))
|
||||
navigation_active = not navigation_agent.is_target_reached()
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
[ext_resource type="PackedScene" uid="uid://xykil2ydlxoc" path="res://assets/3rdparty/KayKit_Adventurers_1.0_EXTRA/Characters/gltf/Rogue_Hooded.glb" id="1_25fog"]
|
||||
[ext_resource type="Script" path="res://objects/non_player_character.gd" id="1_c2apr"]
|
||||
[ext_resource type="BehaviorTree" uid="uid://dck7kl4210076" path="res://ai/trees/empty.tres" id="2_3dryb"]
|
||||
[ext_resource type="AnimationLibrary" uid="uid://dbaynxuqbkor6" path="res://assets/characters/rogue_animation_library.tres" id="2_sp2o4"]
|
||||
[ext_resource type="BehaviorTree" uid="uid://blccr23qjixws" path="res://ai/trees/pug.tres" id="4_1jdgy"]
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_uynrb"]
|
||||
height = 0.8
|
||||
|
@ -28,6 +28,7 @@ radius = 1.0
|
|||
|
||||
[node name="NonPlayerCharacter" type="CharacterBody3D" groups=["non_player_character"]]
|
||||
script = ExtResource("1_c2apr")
|
||||
behaviour = ExtResource("2_3dryb")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.4, 0)
|
||||
|
@ -60,8 +61,16 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.322685, 0)
|
|||
shape = SubResource("CylinderShape3D_3da0u")
|
||||
|
||||
[node name="BTPlayer" type="BTPlayer" parent="."]
|
||||
behavior_tree = ExtResource("4_1jdgy")
|
||||
behavior_tree = ExtResource("2_3dryb")
|
||||
blackboard_plan = SubResource("BlackboardPlan_yqrfn")
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="NavigationAgent" type="NavigationAgent3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
path_desired_distance = 0.1
|
||||
target_desired_distance = 0.1
|
||||
simplify_path = true
|
||||
debug_enabled = true
|
||||
|
||||
[connection signal="body_entered" from="PlayerDetection" to="." method="_on_player_detection_body_entered"]
|
||||
[connection signal="body_exited" from="PlayerDetection" to="." method="_on_player_detection_body_exited"]
|
||||
|
|
|
@ -39,6 +39,8 @@ enabled=PackedStringArray("res://addons/dialogue_manager/plugin.cfg", "res://add
|
|||
[gdunit4]
|
||||
|
||||
settings/test/test_lookup_folder="tests"
|
||||
settings/common/update_notification_enabled=false
|
||||
settings/test/test_discovery=true
|
||||
|
||||
[global_group]
|
||||
|
||||
|
|
621
world/level.tscn
621
world/level.tscn
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue