extends CharacterBody3D @export var have_dialog : bool = false @export var alrdy_talking : bool = false @export var can_wander : bool = false @onready var sprite_label: Sprite3D = $Sprite3D @onready var anim_player: AnimationPlayer = $character/AnimationPlayer # navigation @export var dest_array:Array[Marker3D] @onready var navigation_agent: NavigationAgent3D = $NavigationAgent3D @onready var idle_timer: Timer = $Timer enum NPCSTATE { IDLE, WALKING } var cur_state : NPCSTATE var cur_destination: Marker3D var speed = 2 func _ready() -> void: sprite_label.visible = false if alrdy_talking: await get_tree().create_timer( randf_range(1.0, 2.5) ).timeout anim_player.play("RootAction") if can_wander: _set_state( NPCSTATE.IDLE ) func _on_timer_timeout() -> void: decide_next_state() func _set_state(new_state:NPCSTATE): cur_state = new_state match cur_state: NPCSTATE.IDLE: idle_timer.start( randf_range(1, 2) ) anim_player.play("RootAction", -1, 10) NPCSTATE.WALKING: anim_player.play("RootAction_001", -1, 2.5) func _physics_process(delta: float) -> void: match cur_state: NPCSTATE.IDLE: pass NPCSTATE.WALKING: var next_path_pos:Vector3 = navigation_agent.get_next_path_position() var new_vel : Vector3 = global_position.direction_to( next_path_pos ) * speed velocity = new_vel var look_at_target : Vector3 = Vector3( next_path_pos.x, global_position.y, next_path_pos.z ) if not global_position.is_equal_approx( look_at_target ): look_at( look_at_target ) move_and_slide() func decide_next_state(): if cur_state == NPCSTATE.IDLE: cur_destination = dest_array.pick_random() navigation_agent.target_position = cur_destination.global_position _set_state( NPCSTATE.WALKING ) func _on_area_3d_body_entered(body: Node3D) -> void: if have_dialog and body.is_in_group("player"): sprite_label.visible = true body.set_dialog_mode( global_position ) func _on_area_3d_body_exited(body: Node3D) -> void: if have_dialog and body.is_in_group("player"): sprite_label.visible = false body.set_dialog_mode() func _on_navigation_agent_3d_navigation_finished() -> void: _set_state( NPCSTATE.IDLE )