215 lines
7.1 KiB
C#
215 lines
7.1 KiB
C#
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();
|
||
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
}
|