TinyAdventure/objects/non_player_character.gd

123 lines
4.0 KiB
GDScript

class_name NonPlayerCharacter
extends CharacterBody3D
@export var reacts_to_player:bool = true :
set (value):
reacts_to_player = _set_reacts_to_player(value)
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
#@export var behaviour_blackboard_plan:BlackboardPlan = null:
#set (value):
#behaviour_blackboard_plan = value
#if is_instance_valid(bt_player):
#bt_player.blackboard_plan = behaviour_blackboard_plan
#get:
# return behaviour_blackboard_plan
@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 = 2.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:
player_detection.monitoring = value
return value
func _ready() -> void:
player_detection.monitoring = reacts_to_player
geometry = find_child("Geometry")
if geometry == null:
geometry = default_geometry
else:
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()
var current_path:PackedVector3Array = navigation_agent.get_current_navigation_path()
var path_length:float = 0
for i in range(1, current_path.size()):
path_length = path_length + (current_path[i] - current_path[i - 1]).length()
if DebugSystem.debug_npc == self: DebugDraw3D.draw_point_path(current_path, DebugDraw3D.POINT_TYPE_SPHERE, 0.02)
if is_nan(next_position.length()):
breakpoint
var vector_to_target:Vector3 = next_position - global_position
var distance:float = vector_to_target.length()
if is_nan(distance):
breakpoint
if navigation_agent.is_target_reached():
print ("Target reached. Distance: %s" % navigation_agent.distance_to_target())
navigation_active = false
else:
var direction = (vector_to_target) / distance
basis = Basis.looking_at(-direction)
velocity = direction * SPEED
move_and_slide()
func _on_player_detection_body_entered(body: Node3D) -> void:
if body is Player:
tracking_node = body
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
navigation_active = not navigation_agent.is_target_reached()
func is_navigation_target_reached() -> bool:
return navigation_agent.distance_to_target() < navigation_agent.target_desired_distance or navigation_agent.is_target_reached() or not navigation_active