extends State class_name CharacterState @export var character: CharacterBody3D @export var move_speed: float = 3 @export var body_turn_speed: float = 3 @export var head_turn_speed: float = 6.0 @export var can_see: bool = true # indicates whether the character is able to see things in the state @export var poi_investigate: bool = false @export var poi_change_to_search: bool = false @export var poi_update_waypoint_immediately: bool = false var move_target var look_target func character_has_target(): if character.player_last_seen != null: return true if character.point_of_interest != null: return true return false func update_move_target(): if character.player_last_seen != null: return character.player_last_seen elif character.point_of_interest != null: return character.point_of_interest["point"] else: return character.global_position func search_on_lost_target(): if !character.is_player_visible(): Transitioned.emit(self, "attack") func move_target_adj(position): return Vector3(position.x, character.global_position.y, position.z) func rotate_to_face2D(object, target, target_offset_angle, delta, turn_speed): #to allow both nodes and positions to be passed to this function, test the target and use Vector3 coords var target_transformed if target == null: target_transformed = object.global_position elif target is Vector3: target_transformed = target elif target is Node3D: target_transformed = target.global_position var pos2d = Vector2(object.global_position.x, object.global_position.z) var target_pos2d = Vector2(target_transformed.x, target_transformed.z) var direction = (pos2d - target_pos2d) return lerp_angle(object.global_rotation.y, atan2(direction.x, direction.y) + deg_to_rad(target_offset_angle), delta * turn_speed) func rotate_to_face3D(object: Node3D, target, target_offset_angle: Vector3, delta: float, turn_speed: float): if target == null: return var target_positon if target is Vector3: target_positon = target else: target_positon = target.global_position var desired_rotation = object.global_transform.looking_at(target_positon, Vector3.UP).basis.get_euler() var current_rotation = object.global_rotation #Interpolate each axis current_rotation.x = lerp_angle(current_rotation.x, desired_rotation.x + target_offset_angle.x, delta * turn_speed) current_rotation.y = lerp_angle(current_rotation.y, desired_rotation.y + target_offset_angle.y, delta * turn_speed) current_rotation.z = lerp_angle(current_rotation.z, desired_rotation.z + target_offset_angle.z, delta * turn_speed) #clamp pitch var max_downward_pitch = deg_to_rad(85) var min_upward_pitch = deg_to_rad(-45) current_rotation.x = clamp(current_rotation.x, min_upward_pitch, max_downward_pitch) object.global_rotation = current_rotation func move_to_nav_point(delta): var destination = character.nav_agent.get_next_path_position() var local_destination = destination - character.global_position var new_velocity = local_destination.normalized() * move_speed character.nav_agent.set_velocity(new_velocity) character.global_rotation.y = rotate_to_face2D(character, destination, 0, delta, body_turn_speed) func velocity_computed(safe_velocity): character.velocity = character.velocity.move_toward(safe_velocity, .25) func update_minimap(priority, duration, color): SignalBus.emit_signal("ui_minimap_point", character, character.global_position, 1, duration, color)