extends Node const SPEED := 3.0 const ATTACK_RANGE := 2.0 const REGEN_FAST := 0.10 const REGEN_SLOW := 0.01 @onready var enemy: CharacterBody3D = get_parent() @onready var nav_agent: NavigationAgent3D = get_parent().get_node("NavigationAgent3D") func _physics_process(delta: float) -> void: match enemy.state: enemy.State.IDLE: enemy.velocity.x = 0 enemy.velocity.z = 0 enemy.State.CHASE: _chase() enemy.State.RETURN: _return_to_spawn(delta) func _chase() -> void: if not is_instance_valid(enemy.target): enemy.state = enemy.State.RETURN return var dist_to_target := enemy.global_position.distance_to(enemy.target.global_position) if dist_to_target <= ATTACK_RANGE: enemy.state = enemy.State.ATTACK return nav_agent.target_position = enemy.target.global_position var next_pos := nav_agent.get_next_path_position() var direction := (next_pos - enemy.global_position).normalized() direction.y = 0 enemy.velocity.x = direction.x * SPEED enemy.velocity.z = direction.z * SPEED func _return_to_spawn(delta: float) -> void: var dist := enemy.global_position.distance_to(enemy.spawn_position) if dist < 1.0: enemy.state = enemy.State.IDLE enemy.velocity.x = 0 enemy.velocity.z = 0 return nav_agent.target_position = enemy.spawn_position var next_pos := nav_agent.get_next_path_position() var direction := (next_pos - enemy.global_position).normalized() direction.y = 0 enemy.velocity.x = direction.x * SPEED enemy.velocity.z = direction.z * SPEED _regenerate(delta) func _regenerate(delta: float) -> void: var health: Node = enemy.get_node("Health") if health.current_health < health.max_health: var rate: float = REGEN_FAST if health.current_health < health.max_health else REGEN_SLOW if health.current_health >= health.max_health * 0.99: rate = REGEN_SLOW health.current_health = min(health.current_health + health.max_health * rate * delta, health.max_health) EventBus.health_changed.emit(enemy, health.current_health, health.max_health)