extends Node3D # Камень преследует локального игрока, обходя препятствия по навмешу, и ловит его. @export var speed := 12.0 # Скорость движения @export var turn_speed := 6.0 # Как быстро разворачивается к игроку @export var catch_distance := 3.0 # С какого расстояния (по горизонтали) ловит игрока @export var catch_height := 4.0 # Игрока выше этого над камнем не достать @export var repath_distance := 1.0 # Пересчитываем путь, когда игрок сместился на столько @onready var agent: NavigationAgent3D = $NavigationAgent3D @onready var start_transform := global_transform var player: Node3D = null func _ready() -> void: agent.target_desired_distance = 1.0 agent.path_desired_distance = 1.5 agent.path_height_offset = 0.25 # Навмеш лежит чуть выше пола func _physics_process(delta: float) -> void: if player == null: player = get_tree().get_first_node_in_group("local_player") as Node3D if player == null: return if player.has_signal("respawned"): player.respawned.connect(_on_player_respawned) # Пока игрок лежит — стоим над ним if player.get("is_dead"): return var flat := player.global_position - global_position var dy := flat.y flat.y = 0.0 if flat.length() <= catch_distance and absf(dy) <= catch_height: _face(flat, delta) if player.has_method("die"): player.die() return var step: Vector3 var map := agent.get_navigation_map() if NavigationServer3D.map_get_iteration_id(map) > 0: if agent.target_position.distance_to(player.global_position) > repath_distance: agent.target_position = player.global_position if not agent.is_navigation_finished(): step = agent.get_next_path_position() - global_position # Навмеш ещё не готов или игрок вне его — идём напрямую if step == Vector3.ZERO: step = flat var d := step.length() if d < 0.001: return global_position += step / d * min(speed * delta, d) _face(Vector3(step.x, 0.0, step.z), delta) # Игрок возродился — возвращаемся на старт, чтобы не поймать его сразу снова func _on_player_respawned() -> void: global_transform = start_transform agent.target_position = global_position # Плавный разворот: модель смотрит вперёд по -Z func _face(dir: Vector3, delta: float) -> void: if dir.length_squared() < 0.0001: return var target_yaw := atan2(-dir.x, -dir.z) rotation.y = lerp_angle(rotation.y, target_yaw, 1.0 - exp(-turn_speed * delta))