125 lines
5.2 KiB
GDScript
125 lines
5.2 KiB
GDScript
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
|
||
|
||
# Не проверяем столкновения при полете - только движение
|