class_name Enemy extends Unit @export var player : Player @export var chasing_range := 30.0 @export var attack_range := 3.0 var attacks := ["Unarmed_Melee_Attack_Punch_A", "Unarmed_Melee_Attack_Punch_B", "Unarmed_Melee_Attack_Kick"] @onready var nav_agent: NavigationAgent3D = $NavigationAgent3D func _ready() -> void: health = maximum_health stamina = maximum_stamina state_changed.connect(_on_state_changed) func _physics_process(_delta: float) -> void: if state == States.dead: return if player == null: return if player.state == States.dead: state = States.idle return var distance = global_position.distance_to(player.global_position) if distance > chasing_range: state = States.idle elif distance <= chasing_range and distance >= attack_range: state = States.chasing if distance <= attack_range: state = States.attacking func _on_state_changed(new_state: States) -> void: name_changed.emit(unit_name, States.keys()[new_state]) match new_state: States.idle: #TODO: Random movement _on_velocity_computed(Vector3.ZERO) States.chasing: nav_agent.set_target_position(player.position) if nav_agent.is_navigation_finished() or nav_agent.is_target_reached(): return var next_path_position: Vector3 = nav_agent.get_next_path_position() model.look_at(next_path_position) var new_velocity: Vector3 = global_position.direction_to(next_path_position) * speed _on_velocity_computed(new_velocity) States.attacking: if enough_stamina_available(attack_cost): use_stamina(attack_cost) anim_state.travel(attacks.pick_random()) States.dead: player.gold += 1 #TODO: Slightly disapear func _on_velocity_computed(safe_velocity: Vector3) -> void: velocity = safe_velocity var vy = velocity.y velocity.y = 0 var vl = velocity * model.transform.basis anim_tree.set("parameters/IWR/blend_position", Vector2(vl.x, -vl.z) / speed) velocity.y = vy move_and_slide()