sea-battle/Assets/Scripts/CameraController.cs
2026-05-15 13:02:11 +03:00

215 lines
7.1 KiB
C#
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.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour
{
[Header("Refs")]
public Transform pivot; // если не задан — возьмём свой transform
public GameManager gameManager; // чтобы блокировать в UI
public Transform shipPlacementCameraPosition;
public Transform mainMenuCameraPosition;
public Transform gameplayCameraPosition;
[Header("Input")]
public ButtonPinMapping rotateLeftKey;
public ButtonPinMapping rotateRightKey;
[Header("Speeds")]
public float rotateSpeed = 90f; // ручное вращение
public float returnSpeed = 120; // возврат в "домой"
private Quaternion _homeRotation;
private float _turnHoldTime = 0f;
[Tooltip("Секунд удержания до включения вращения камеры")]
public float turnHoldThreshold = 0.3f;
public float cameraMoveDuration = 1.0f; // Время перемещения в секундах
private int countDown = 0;
private float lastTapTime = 0f;
[Tooltip("Окно времени для распознавания двойного нажатия (сек)")]
public float doubleTapWindow = 0.4f;
private bool isReturning = false;
[Tooltip("Центр вращения камеры во время расстановки кораблей (пустой GO у поля игрока)")]
[SerializeField] private Transform shipPlacementPivotPoint;
/// <summary>Исходная мировая позиция cameraPivot — восстанавливается вне режима расстановки.</summary>
private Vector3 _defaultPivotPosition;
public void CaptureHomeNow() => _homeRotation = pivot.rotation;
void Awake()
{
if (!pivot) pivot = transform;
// по умолчанию "дом" — текущий поворот на старте
_homeRotation = this.transform.rotation;
}
void Start()
{
if (pivot != null)
_defaultPivotPosition = pivot.position;
}
void Update()
{
float dir = 0f;
// задержка при расстановке кораблей
if (gameManager.currentState == GameState.ShipPlacement)
{
if (In.GetButton(rotateLeftKey) || In.GetButton(rotateRightKey))
{
_turnHoldTime += Time.deltaTime;
if (_turnHoldTime < turnHoldThreshold) return;
if (In.GetButton(rotateRightKey))
{
dir -= 1f;
}
if (In.GetButton(rotateLeftKey))
{
dir += 1f;
}
if (dir != 0f && pivot)
pivot.Rotate(Vector3.up, dir * rotateSpeed * Time.deltaTime, Space.World);
return;
}
else _turnHoldTime = 0f;
}
if(gameManager != null && (gameManager.currentInputMode == GameManager.InputMode.UI
|| gameManager.currentInputMode == GameManager.InputMode.Settings))
return;
// Обнаружение двойного нажатия (time-window)
if (In.GetButtonDown(rotateLeftKey) || In.GetButtonDown(rotateRightKey))
{
if (Time.time - lastTapTime <= doubleTapWindow)
{
countDown++;
}
else
{
countDown = 1;
}
lastTapTime = Time.time;
if (countDown >= 2)
{
isReturning = true;
countDown = 0;
}
}
// Если в режиме возврата — двигаем камеру к дому
if (isReturning)
{
pivot.rotation = Quaternion.RotateTowards(pivot.rotation, _homeRotation, returnSpeed * Time.deltaTime);
if (Quaternion.Angle(pivot.rotation, _homeRotation) < 0.01f)
{
// Vector3 dir = pivot.rotation.eulerAngles;
// if (targetCursor != null) targetCursor.SwitchButton(dir);
isReturning = false;
}
}
if (In.GetButton(rotateRightKey))
{
dir -= 1f;
}
if (In.GetButton(rotateLeftKey))
{
dir += 1f;
}
if (dir != 0f && pivot)
pivot.Rotate(Vector3.up, dir * rotateSpeed * Time.deltaTime, Space.World);
}
public void MoveCameraToMainMenu() => MoveCameraTo(mainMenuCameraPosition);
public void MoveCameraToShipPlacement() => MoveCameraTo(shipPlacementCameraPosition);
public void MoveCameraToGameplay() => MoveCameraTo(gameplayCameraPosition);
public void MoveCameraTo(Transform target)
{
if (target != null)
{
StopAllCoroutines();
StartCoroutine(MoveCameraSmoothly(target));
}
}
private IEnumerator MoveCameraSmoothly(Transform target)
{
Transform cam = this.transform;
// Отсоединяем камеру от пивота на время перемещения —
// иначе поворот пивота кнопками во время полёта камеры сдвигает её конечную позицию
cam.SetParent(null);
Vector3 startPos = cam.position;
Quaternion startRot = cam.rotation;
Vector3 endPos = target.position;
Quaternion endRot = target.rotation;
float elapsed = 0f;
while (elapsed < cameraMoveDuration)
{
float t = elapsed / cameraMoveDuration;
cam.position = Vector3.Lerp(startPos, endPos, t);
cam.rotation = Quaternion.Slerp(startRot, endRot, t);
elapsed += Time.deltaTime;
yield return null;
}
cam.position = endPos;
cam.rotation = endRot;
// Сбрасываем пивот и возвращаем камеру обратно как дочерний объект
if (pivot != null)
{
pivot.rotation = Quaternion.identity;
// Перемещаем пивот: во время расстановки кораблей — к полю игрока,
// в остальных состояниях — обратно на дефолтную позицию
bool isShipPlacement = (target == shipPlacementCameraPosition);
if (isShipPlacement && shipPlacementPivotPoint != null)
pivot.position = shipPlacementPivotPoint.position;
else
pivot.position = _defaultPivotPosition;
// worldPositionStays: true — локальные координаты пересчитаются под новый пивот
cam.SetParent(pivot, true);
CaptureHomeNow();
}
}
}