TinyAdventure/objects/non_player_character.gd

147 lines
4.9 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
@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
@onready var dash_collision_shape: CollisionShape3D = %DashCollisionShape
@onready var dash_detection_area: Area3D = %DashDetectionArea
const SPEED = 2.0
const JUMP_VELOCITY = 4.5
const VELOCITY_DAMPING = 20.0
var tool_damage:bool = false
var tracking_node:Node3D = null
var navigation_active:bool = false
var is_dash_active:bool = false:
set(value):
is_dash_active = value
dash_collision_shape.disabled = not is_dash_active
dash_detection_area.monitoring = is_dash_active
get:
return is_dash_active
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(behaviour):
bt_player.behavior_tree = behaviour
if is_instance_valid(behaviour_blackboard_plan):
bt_player.blackboard.set_parent(behaviour_blackboard_plan.create_blackboard(self))
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
var path_remainder:float = path_length / (SPEED * delta)
if navigation_agent.is_navigation_finished() or path_remainder <= navigation_agent.target_desired_distance:
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 * (minf(1.0, path_remainder * 0.9))
# print ("scale %f" % (path_remainder))
move_and_slide()
var speed = velocity.length()
if speed > 0:
velocity = velocity - (velocity) * min(VELOCITY_DAMPING * delta / speed, 1.0)
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 query_navigation_path(target_position: Vector3) -> PackedVector3Array:
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
navigation_query_parameters.simplify_path = true
if NavigationServer3D.map_get_iteration_id(navigation_query_parameters.map) == 0:
return PackedVector3Array()
NavigationServer3D.query_path(navigation_query_parameters, navigation_query_result)
return navigation_query_result.path.duplicate()
func is_target_navigatable(target_position: Vector3) -> bool:
var query_path: PackedVector3Array = query_navigation_path(target_position)
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_navigation_finished()
func is_navigation_finished() -> bool:
return navigation_agent.is_navigation_finished()
func is_navigation_target_reached() -> bool:
return navigation_agent.is_target_reached()
func _on_dash_detection_area_body_entered(_body: Node3D) -> void:
print ("hitting player!")