147 lines
4.9 KiB
GDScript
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!")
|