Files
acrion-rog-client/scripts/player.gd
Redsandy 7980e0add8 init
2026-01-18 20:56:24 +03:00

250 lines
9.0 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Unit
class_name Player
# Класс игрока с управлением WASD
@export var mouse_sensitivity: float = 0.003
@export var dash_speed: float = 25.0 # Скорость рывка
@export var dash_duration: float = 0.2 # Длительность рывка
@export var dash_cooldown: float = 1.0 # Перезарядка рывка
@export var straight_projectile_scene: PackedScene = null # Сцена прямого снаряда
@export var parabolic_projectile_scene: PackedScene = null # Сцена параболического снаряда
@export var projectile_damage: float = 20.0
@export var projectile_speed: float = 20.0
@export var explosion_radius: float = 3.0
var camera_angle: float = 0.0
var is_dashing: bool = false
var dash_timer: float = 0.0
var dash_cooldown_timer: float = 0.0
var dash_direction: Vector3 = Vector3.ZERO
signal dash_started
signal dash_ended
signal dash_cooldown_changed(remaining_time: float)
func _ready():
super._ready()
# Игрок белый
var mesh_instance = get_node_or_null("MeshInstance3D")
if mesh_instance:
var material = StandardMaterial3D.new()
material.albedo_color = Color.WHITE
mesh_instance.material_override = material
func _input(event):
# Обработка рывка
if event.is_action_pressed("dash") and dash_cooldown_timer <= 0.0 and not is_dashing:
perform_dash()
# Обработка стрельбы (левая кнопка мыши)
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
shoot_straight_projectile()
# Обработка броска (правая кнопка мыши)
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
throw_parabolic_projectile()
func _physics_process(delta):
# Обновляем таймеры
var previous_cooldown = dash_cooldown_timer
if dash_cooldown_timer > 0.0:
dash_cooldown_timer -= delta
dash_cooldown_timer = max(0.0, dash_cooldown_timer)
# Эмитим сигнал только если значение изменилось
if abs(previous_cooldown - dash_cooldown_timer) > 0.01:
dash_cooldown_changed.emit(dash_cooldown_timer)
# Поворачиваем игрока в сторону курсора мыши
update_rotation_to_mouse()
# Получаем направление движения от клавиатуры
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction = Vector3(input_dir.x, 0, input_dir.y)
# Обработка рывка
if is_dashing:
dash_timer -= delta
if dash_timer <= 0.0:
end_dash()
else:
# Во время рывка двигаемся с увеличенной скоростью
velocity.x = dash_direction.x * dash_speed
velocity.z = dash_direction.z * dash_speed
else:
# Обычное движение
if direction.length() > 0:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
# Применяем гравитацию
if not is_on_floor():
velocity.y -= 9.8 * delta
else:
velocity.y = 0
super._physics_process(delta)
func update_rotation_to_mouse():
# Получаем камеру из сцены
var camera = get_viewport().get_camera_3d()
if not camera:
return
# Получаем позицию курсора мыши на экране
var mouse_pos = get_viewport().get_mouse_position()
# Создаем луч от камеры через позицию курсора
var from = camera.project_ray_origin(mouse_pos)
var to = from + camera.project_ray_normal(mouse_pos) * 1000.0
# Создаем запрос для raycast
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(from, to)
query.collision_mask = 1 # Слой земли
# Выполняем raycast
var result = space_state.intersect_ray(query)
if result:
# Получаем точку пересечения
var target_point = result.position
# Поворачиваем игрока в сторону курсора (только по оси Y)
var look_direction = (target_point - global_position)
look_direction.y = 0 # Игнорируем вертикальную составляющую
if look_direction.length() > 0.1:
look_at(global_position + look_direction, Vector3.UP)
func perform_dash():
# Получаем направление движения
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction = Vector3(input_dir.x, 0, input_dir.y)
# Если игрок не двигается, рывок вперед (по направлению взгляда или вверх)
if direction.length() < 0.1:
direction = Vector3(0, 0, -1) # Вперед по умолчанию
# Нормализуем направление
dash_direction = direction.normalized()
# Запускаем рывок
is_dashing = true
dash_timer = dash_duration
dash_cooldown_timer = dash_cooldown
dash_started.emit()
func end_dash():
is_dashing = false
dash_timer = 0.0
dash_ended.emit()
func shoot_straight_projectile():
if not straight_projectile_scene:
return
# Получаем точку прицеливания через raycast
var target_point = get_mouse_target_point()
if not target_point:
return
# Создаем снаряд
var projectile = straight_projectile_scene.instantiate() as StraightProjectile
if not projectile:
return
# Устанавливаем параметры
projectile.owner_unit = self
projectile.damage = projectile_damage
projectile.speed = projectile_speed
projectile.is_explosive = false
# Направление полета
var shoot_position = global_position + Vector3.UP * 1.0 # Немного выше игрока
var direction = (target_point - shoot_position).normalized()
projectile.direction = direction
# Позиция и поворот
projectile.global_position = shoot_position
projectile.look_at(shoot_position + direction, Vector3.UP)
# Добавляем в сцену
var scene_root = get_tree().current_scene
if not scene_root:
scene_root = get_tree().root.get_child(get_tree().root.get_child_count() - 1)
scene_root.add_child(projectile)
func throw_parabolic_projectile():
if not parabolic_projectile_scene:
# Пробуем загрузить вручную
parabolic_projectile_scene = load("res://scenes/parabolic_projectile.tscn") as PackedScene
if not parabolic_projectile_scene:
return
# Получаем точку прицеливания через raycast (на плоскости)
var target_point = get_mouse_target_point()
# Убеждаемся, что целевая точка на уровне земли (Y = 0)
# Если кликнули на противника или другой объект, используем его X и Z, но Y ставим на землю
target_point.y = 0.0
# Позиция запуска
var throw_position = global_position + Vector3.UP * 1.0
# Создаем снаряд
var projectile = parabolic_projectile_scene.instantiate()
if not projectile:
return
# Устанавливаем параметры ДО добавления в сцену
projectile.owner_unit = self
projectile.damage = projectile_damage
projectile.speed = projectile_speed
projectile.is_explosive = true
projectile.explosion_radius = explosion_radius
# Устанавливаем позицию
projectile.global_position = throw_position
# Целевая позиция (на уровне земли) - устанавливаем ДО _ready()
projectile.target_position = target_point
# Добавляем в сцену (после установки всех параметров)
var scene_root = get_tree().current_scene
if not scene_root:
scene_root = get_tree().root.get_child(get_tree().root.get_child_count() - 1)
scene_root.add_child(projectile)
func get_mouse_target_point() -> Vector3:
# Получаем камеру
var camera = get_viewport().get_camera_3d()
if not camera:
return global_position + transform.basis.z * -10.0
# Получаем позицию курсора мыши
var mouse_pos = get_viewport().get_mouse_position()
# Создаем луч от камеры
var from = camera.project_ray_origin(mouse_pos)
var ray_dir = camera.project_ray_normal(mouse_pos)
var to = from + ray_dir * 1000.0
# Raycast
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(from, to)
query.collision_mask = 1
var result = space_state.intersect_ray(query)
if result:
return result.position
# Если не попали ни во что, вычисляем точку на плоскости земли
if ray_dir.y < -0.01: # Луч направлен вниз
var t = -from.y / ray_dir.y
return from + ray_dir * t
# Если луч не направлен вниз, используем точку перед игроком
return global_position + transform.basis.z * -10.0