init
This commit is contained in:
249
scripts/player.gd
Normal file
249
scripts/player.gd
Normal file
@@ -0,0 +1,249 @@
|
||||
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
|
||||
Reference in New Issue
Block a user