extends CharacterBody3D @export var chase_speed: float = 4.0 @export var detection_range: float = 100.0 @export var sprite_scale: float = 5.0 @onready var sight_ray: RayCast3D = $SightRay @onready var nav_agent: NavigationAgent3D = $NavigationAgent3D @onready var anim_sprite: AnimatedSprite3D = $AnimatedSprite3D var player: Node3D var can_see_player: bool = false var nav_ready: bool = false enum State { IDLE, CHASE, SEARCH } var state: State = State.IDLE var last_state: State = State.IDLE func _ready() -> void:     scale = Vector3(1, 1, 1)     $CollisionShape3D.scale = Vector3(1, 1, 1)     anim_sprite.scale = Vector3(sprite_scale, sprite_scale, sprite_scale)     global_position.y = 0.5     player = get_tree().get_first_node_in_group("player")     if player:         print("Tiger found the player: ", player.name)     else:         print("Tiger cnt find player ")     anim_sprite.billboard = BaseMaterial3D.BILLBOARD_ENABLED     _play_anim("idle")     await get_tree().physics_frame     await get_tree().physics_frame     if player:         nav_agent.target_position = player.global_position     nav_ready = true     print(" Nav readyTiger pos: ", global_position) func _physics_process(delta: float) -> void:     if not player or not nav_ready:         return     _update_sight()     _update_state()     _move(delta)     _update_animation() func _update_sight() -> void:     var to_player = player.global_position - global_position     var distance = to_player.length()     if distance > detection_range:         can_see_player = false         return     sight_ray.global_position = global_position + Vector3(0, 1.5, 0)     sight_ray.target_position = sight_ray.to_local(         player.global_position + Vector3(0, 1.5, 0)     )     sight_ray.force_raycast_update()     if sight_ray.is_colliding():         var hit = sight_ray.get_collider()         can_see_player = hit == player     else:         can_see_player = true func _update_state() -> void:     match state:         State.IDLE:             if can_see_player:                 state = State.CHASE                 print("tgr State: CHASE")         State.CHASE:             if can_see_player:                 nav_agent.target_position = player.global_position             else:                 state = State.SEARCH                 print("tgr State: SEARCH")         State.SEARCH:             if can_see_player:                 state = State.CHASE                 print("tgr State: CHASE")             elif nav_agent.is_navigation_finished():                 state = State.IDLE                 print("tgr State: IDLE") func _move(delta: float) -> void:     if state == State.IDLE or nav_agent.is_navigation_finished():         velocity.x = 0         velocity.z = 0         if not is_on_floor():             velocity.y -= 9.8 * delta         move_and_slide()         return     var next_pos = nav_agent.get_next_path_position()     var diff = next_pos - global_position     diff.y = 0     var distance_to_next = diff.length()     if distance_to_next < 0.1:         velocity.x = 0         velocity.z = 0     else:         var direction = diff.normalized()         velocity.x = direction.x * chase_speed         velocity.z = direction.z * chase_speed     if not is_on_floor():         velocity.y -= 9.8 * delta     else:         velocity.y = 0     move_and_slide() func _update_animation() -> void:     var cam = get_viewport().get_camera_3d()     if cam and velocity.length() > 0.1:         var local_vel = cam.global_transform.basis.inverse() * velocity         anim_sprite.flip_h = local_vel.x < 0     if state == last_state:         return     last_state = state     match state:         State.IDLE:             _play_anim("idle")         State.CHASE, State.SEARCH:             _play_anim("run") func _play_anim(anim_name: String) -> void:     if anim_sprite.sprite_frames and \         anim_sprite.sprite_frames.has_animation(anim_name) and \         anim_sprite.animation != anim_name:         anim_sprite.play(anim_name)