198 lines
8.0 KiB
C#
198 lines
8.0 KiB
C#
using UnityEngine;
|
||
|
||
public class CameraController : MonoBehaviour
|
||
{
|
||
[Header("Настройки позиции камеры (Зум)")]
|
||
public float distance = 10f;
|
||
public float minDistance = 3f;
|
||
public float maxDistance = 30f;
|
||
public float zoomSpeed = 0.05f;
|
||
|
||
[Header("Настройки цели (Ось Y)")]
|
||
public float targetY = 0f;
|
||
public float minTargetY = 0f;
|
||
public float maxTargetY = 15f;
|
||
public float moveTargetSpeed = 0.02f;
|
||
public float addingHeight = 3f;
|
||
|
||
[Header("Настройки вращения")]
|
||
public float rotationSpeed = 0.2f;
|
||
[SerializeField]
|
||
private float currentAngle = -45f;
|
||
|
||
[Header("Настройки смещения (Pan - НОВОЕ)")]
|
||
[Tooltip("Скорость смещения камеры по горизонтали")]
|
||
public float panSpeed = 0.03f;
|
||
[Tooltip("При каком отдалении камеры разрешено смещение? (Если отдалить дальше - смещение сбросится)")]
|
||
public float zoomThresholdForPan = 15f;
|
||
[Tooltip("Максимальное смещение от центра комнаты")]
|
||
public float maxPanDistance = 10f;
|
||
|
||
[Header("Настройки плавности (Сглаживание)")]
|
||
[Range(0.01f, 0.5f)]
|
||
public float smoothTime = 0.1f;
|
||
public float touchDeadZone = 1.5f;
|
||
|
||
// ЦЕЛЕВЫЕ значения
|
||
private float _targetAngle;
|
||
private float _targetY;
|
||
private float _targetDistance;
|
||
|
||
// НОВОЕ: Целевое и текущее смещение по осям X и Z
|
||
private Vector2 _targetPanOffset;
|
||
private Vector2 _currentPanOffset;
|
||
|
||
// Внутренние переменные скорости для SmoothDamp
|
||
private float _angleVelocity;
|
||
private float _yVelocity;
|
||
private float _distanceVelocity;
|
||
private Vector2 _panVelocity; // Скорость для смещения
|
||
|
||
void Start()
|
||
{
|
||
_targetAngle = currentAngle;
|
||
_targetY = targetY;
|
||
_targetDistance = distance;
|
||
_targetPanOffset = Vector2.zero;
|
||
_currentPanOffset = Vector2.zero;
|
||
|
||
UpdateCameraPosition();
|
||
}
|
||
|
||
void LateUpdate()
|
||
{
|
||
HandleInput();
|
||
CheckPanReset(); // Проверяем, не пора ли сбросить смещение
|
||
SmoothMovement();
|
||
UpdateCameraPosition();
|
||
}
|
||
|
||
private void HandleInput()
|
||
{
|
||
// === 1. УПРАВЛЕНИЕ ОДНИМ ПАЛЬЦЕМ (Вращение и высота) ===
|
||
if (Input.touchCount == 1)
|
||
{
|
||
Touch touch = Input.GetTouch(0);
|
||
|
||
if (touch.phase == TouchPhase.Moved && touch.deltaPosition.sqrMagnitude > touchDeadZone * touchDeadZone)
|
||
{
|
||
_targetAngle += touch.deltaPosition.x * rotationSpeed;
|
||
_targetY -= touch.deltaPosition.y * moveTargetSpeed;
|
||
_targetY = Mathf.Clamp(_targetY, minTargetY, maxTargetY);
|
||
}
|
||
}
|
||
// === 2. УПРАВЛЕНИЕ ДВУМЯ ПАЛЬЦАМИ (Зум и Смещение) ===
|
||
else if (Input.touchCount == 2)
|
||
{
|
||
Touch touch0 = Input.GetTouch(0);
|
||
Touch touch1 = Input.GetTouch(1);
|
||
|
||
// -- Логика Зума --
|
||
Vector2 touch0PrevPos = touch0.position - touch0.deltaPosition;
|
||
Vector2 touch1PrevPos = touch1.position - touch1.deltaPosition;
|
||
|
||
float prevMagnitude = (touch0PrevPos - touch1PrevPos).magnitude;
|
||
float currentMagnitude = (touch0.position - touch1.position).magnitude;
|
||
|
||
float difference = currentMagnitude - prevMagnitude;
|
||
|
||
if (Mathf.Abs(difference) > touchDeadZone)
|
||
{
|
||
_targetDistance -= difference * zoomSpeed;
|
||
_targetDistance = Mathf.Clamp(_targetDistance, minDistance, maxDistance);
|
||
}
|
||
|
||
// -- НОВОЕ: Логика смещения (Панорамирование) --
|
||
// Разрешаем смещение только если камера достаточно близко
|
||
if (_targetDistance <= zoomThresholdForPan)
|
||
{
|
||
// Берем среднее движение двух пальцев
|
||
Vector2 avgDelta = (touch0.deltaPosition + touch1.deltaPosition) / 2f;
|
||
ApplyPan(avgDelta.x, avgDelta.y);
|
||
}
|
||
}
|
||
// === 3. МЫШЬ (Для редактора ПК) ===
|
||
else
|
||
{
|
||
// Левая кнопка - Вращение и высота
|
||
if (Input.GetMouseButton(0))
|
||
{
|
||
_targetAngle += Input.GetAxis("Mouse X") * rotationSpeed * 20f;
|
||
_targetY -= Input.GetAxis("Mouse Y") * moveTargetSpeed * 20f;
|
||
_targetY = Mathf.Clamp(_targetY, minTargetY, maxTargetY);
|
||
}
|
||
// НОВОЕ: Правая кнопка - Смещение (Pan)
|
||
else if (Input.GetMouseButton(1) && _targetDistance <= zoomThresholdForPan)
|
||
{
|
||
ApplyPan(Input.GetAxis("Mouse X") * 20f, Input.GetAxis("Mouse Y") * 20f);
|
||
}
|
||
|
||
// Зум колесиком мыши
|
||
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
||
if (scroll != 0)
|
||
{
|
||
_targetDistance -= scroll * zoomSpeed * 100f;
|
||
_targetDistance = Mathf.Clamp(_targetDistance, minDistance, maxDistance);
|
||
}
|
||
}
|
||
}
|
||
|
||
// НОВЫЙ МЕТОД: Применение смещения относительно текущего поворота камеры
|
||
private void ApplyPan(float deltaX, float deltaY)
|
||
{
|
||
// Высчитываем векторы "вправо" и "вперед" для камеры, игнорируя наклон (ось Y)
|
||
Vector3 right = transform.right;
|
||
right.y = 0;
|
||
right.Normalize();
|
||
|
||
Vector3 forward = transform.forward;
|
||
forward.y = 0;
|
||
forward.Normalize();
|
||
|
||
// Умножаем движение пальца/мыши на направление камеры
|
||
Vector3 move = (right * -deltaX) + (forward * -deltaY);
|
||
|
||
_targetPanOffset += new Vector2(move.x, move.z) * panSpeed;
|
||
|
||
// Ограничиваем максимальное смещение, чтобы не улететь за карту
|
||
if (_targetPanOffset.magnitude > maxPanDistance)
|
||
{
|
||
_targetPanOffset = _targetPanOffset.normalized * maxPanDistance;
|
||
}
|
||
}
|
||
|
||
// НОВЫЙ МЕТОД: Сброс смещения при отдалении
|
||
private void CheckPanReset()
|
||
{
|
||
if (_targetDistance > zoomThresholdForPan)
|
||
{
|
||
// Если отдалились слишком сильно - обнуляем целевое смещение.
|
||
// Благодаря SmoothDamp камера вернется в центр плавно!
|
||
_targetPanOffset = Vector2.zero;
|
||
}
|
||
}
|
||
|
||
private void SmoothMovement()
|
||
{
|
||
currentAngle = Mathf.SmoothDamp(currentAngle, _targetAngle, ref _angleVelocity, smoothTime);
|
||
targetY = Mathf.SmoothDamp(targetY, _targetY, ref _yVelocity, smoothTime);
|
||
distance = Mathf.SmoothDamp(distance, _targetDistance, ref _distanceVelocity, smoothTime);
|
||
|
||
// НОВОЕ: Плавно сглаживаем позицию смещения
|
||
_currentPanOffset = Vector2.SmoothDamp(_currentPanOffset, _targetPanOffset, ref _panVelocity, smoothTime);
|
||
}
|
||
|
||
private void UpdateCameraPosition()
|
||
{
|
||
// НОВОЕ: Теперь цель вращения учитывает наше смещение по осям X и Z
|
||
Vector3 targetPoint = new Vector3(_currentPanOffset.x, targetY, _currentPanOffset.y);
|
||
|
||
float radians = currentAngle * Mathf.Deg2Rad;
|
||
|
||
float x = targetPoint.x + distance * Mathf.Sin(radians);
|
||
float z = targetPoint.z + distance * Mathf.Cos(radians);
|
||
|
||
transform.position = new Vector3(x, targetY + addingHeight, z);
|
||
transform.LookAt(targetPoint);
|
||
}
|
||
} |