Загрузка данных


extends CharacterBody3D

@export var SPEED: float = 12.0
@export var GRAVITY: float = 20.0

# Текстуры спины и лица (назначаются в Инспекторе)
@export var texture_back: Texture2D
@export var texture_front: Texture2D

# Чувствительность мыши
@export var MOUSE_SENSITIVITY: float = 0.003

# Настройки зума камеры (дистанция)
@export var MIN_ZOOM: float = 2.0
@export var MAX_ZOOM: float = 12.0
@export var ZOOM_SPEED: float = 0.5

# Ограничения вертикального наклона камеры (в радианах)
@export var MIN_PITCH: float = deg_to_rad(-60.0)
@export var MAX_PITCH: float = deg_to_rad(60.0)

@onready var sprite: Sprite3D = $Sprite3D
@onready var camera_pivot: Node3D = $CameraPivot
@onready var camera: Camera3D = $CameraPivot/Camera3D

func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_VISIBLE

func _input(event: InputEvent) -> void:
	# 1. ПКМ включает/выключает вращение камеры
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_RIGHT:
			if event.pressed:
				Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
			else:
				Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
		
		# 2. ЗУМ (Масштабирование колёсиком мыши)
		elif event.pressed and camera:
			if event.button_index == MOUSE_BUTTON_WHEEL_UP:
				# Приближаем камеру
				camera.position.z = clamp(camera.position.z - ZOOM_SPEED, MIN_ZOOM, MAX_ZOOM)
			elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
				# Отдаляем камеру
				camera.position.z = clamp(camera.position.z + ZOOM_SPEED, MIN_ZOOM, MAX_ZOOM)

	# 3. Вращение точки pivot мышью ПРИ ЗАЖАТОЙ ПКМ
	if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
		if camera_pivot:
			camera_pivot.rotate_y(-event.relative.x * MOUSE_SENSITIVITY)
			camera_pivot.rotate_object_local(Vector3.RIGHT, -event.relative.y * MOUSE_SENSITIVITY)
			camera_pivot.rotation.x = clamp(camera_pivot.rotation.x, MIN_PITCH, MAX_PITCH)

func _physics_process(delta: float) -> void:
	# Гравитация
	if not is_on_floor():
		velocity.y -= GRAVITY * delta

	# 4. Полное WASD движение (Вперед/Назад и Влево/Вправо)
	var input_dir := Vector2.ZERO
	if Input.is_key_pressed(KEY_W) or Input.is_action_pressed("ui_up"):
		input_dir.y -= 1.0
	if Input.is_key_pressed(KEY_S) or Input.is_action_pressed("ui_down"):
		input_dir.y += 1.0
	if Input.is_key_pressed(KEY_A) or Input.is_action_pressed("ui_left"):
		input_dir.x -= 1.0
	if Input.is_key_pressed(KEY_D) or Input.is_action_pressed("ui_right"):
		input_dir.x += 1.0

	input_dir = input_dir.normalized()

	# Движение рассчитывается относительно ориентации Player
	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()

	if direction != Vector3.ZERO:
		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)

	move_and_slide()
	
	_update_sprite_texture()

func _update_sprite_texture() -> void:
	if not sprite or not camera or not camera_pivot:
		return

	# Вычисляем угол поворота CameraPivot вокруг оси Y
	# fmod_p позволяет обрезать угол в диапазон от -PI до PI
	var pivot_y = fmod(camera_pivot.rotation.y, TAU)
	if pivot_y > PI:
		pivot_y -= TAU
	elif pivot_y < -PI:
		pivot_y += TAU

	# Если точка обзора камеры повернулась на переднюю полусферу (угол больше 90° или меньше -90°)
	if abs(pivot_y) > PI / 2.0:
		if texture_front:
			sprite.texture = texture_front
	else:
		if texture_back:
			sprite.texture = texture_back