extends Projectile class_name ParabolicProjectile # Параболический снаряд для броска @export var projectile_gravity: float = 200 @export var arc_height: float = 15.0 # Увеличена высота параболы var target_position: Vector3 = Vector3.ZERO var start_position: Vector3 = Vector3.ZERO var travel_time: float = 0.0 var total_time: float = 0.0 func _ready(): start_position = global_position # Проверяем, что target_position установлен if target_position == Vector3.ZERO: # Если не установлен, используем направление вперед target_position = start_position + Vector3(0, 0, -10.0) target_position.y = start_position.y # Вычисляем горизонтальное расстояние var horizontal_distance = Vector3(start_position.x, 0, start_position.z).distance_to(Vector3(target_position.x, 0, target_position.z)) # Вычисляем правильную траекторию для попадания в цель var horizontal_dir = (target_position - start_position) horizontal_dir.y = 0 # Если цель слишком близко (включая клик на самого игрока), устанавливаем минимальное расстояние и направление if horizontal_distance < 1.0: # Если направление нулевое или очень маленькое, используем направление вперед от игрока if horizontal_dir.length() < 0.1: # Используем направление камеры или направление вперед var camera = get_viewport().get_camera_3d() if camera: var forward = -camera.global_transform.basis.z forward.y = 0 horizontal_dir = forward.normalized() else: horizontal_dir = Vector3(0, 0, -1) # Направление по умолчанию else: horizontal_dir = horizontal_dir.normalized() # Устанавливаем минимальное расстояние horizontal_distance = 1.0 # Обновляем target_position на минимальном расстоянии от стартовой позиции target_position = start_position + horizontal_dir * horizontal_distance target_position.y = 0.0 else: horizontal_dir = horizontal_dir.normalized() # Время подъема до максимальной высоты var time_to_peak = sqrt(2 * arc_height / projectile_gravity) # Время полета вниз (примерно такое же) var time_to_fall = time_to_peak # Общее время полета по вертикали var vertical_time = time_to_peak + time_to_fall # Горизонтальная скорость должна обеспечить попадание в цель за время полета var horizontal_speed = horizontal_distance / vertical_time # Начальная вертикальная скорость для достижения нужной высоты var vertical_speed = sqrt(2 * projectile_gravity * arc_height) # Общее время полета total_time = vertical_time # Устанавливаем начальную скорость velocity = horizontal_dir * horizontal_speed + Vector3.UP * vertical_speed # Вызываем super._ready() после установки velocity super._ready() # Отключаем мониторинг коллизий при полете monitoring = false func _physics_process(delta): if has_hit: return # Если velocity не установлена, не двигаемся if velocity == Vector3.ZERO: return # Проверяем время жизни lifetime_timer -= delta if lifetime_timer <= 0: if is_explosive: explode(global_position) else: queue_free() return travel_time += delta # Сохраняем предыдущую позицию для raycast (если понадобится) previous_position = global_position # Применяем гравитацию velocity.y -= projectile_gravity * delta # Движение снаряда global_position += velocity * delta # Проверяем, достигли ли цели # Проверяем по Y координате (приземление) и по времени полета # НЕ проверяем горизонтальное расстояние, так как это может сработать сразу при близких целях if (global_position.y <= target_position.y + 0.3) and (travel_time >= total_time * 0.5): # Включаем коллизию только при приземлении monitoring = true # Устанавливаем позицию точно в целевую точку global_position = target_position on_hit(target_position) return # Дополнительная проверка по времени полета (на случай, если снаряд не достиг земли) if travel_time >= total_time * 1.2: monitoring = true global_position = target_position on_hit(target_position) return # Не проверяем столкновения при полете - только движение