New paste Repaste Download
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)
Filename: Tiger code. Size: 4kb. View raw, , hex, or download this file.

This paste expires on 2026-05-26 09:23:57.814974+00:00. Pasted through web.