149 lines
6.1 KiB
C#
149 lines
6.1 KiB
C#
using UnityEngine;
|
||
|
||
[RequireComponent(typeof(Camera))]
|
||
public class MapCameraController : MonoBehaviour
|
||
{
|
||
[Header("Настройки карты")]
|
||
[Tooltip("Ссылка на SpriteRenderer вашей карты для определения границ")]
|
||
public SpriteRenderer mapRenderer;
|
||
|
||
[Header("Настройки перемещения")]
|
||
[Tooltip("Скорость перемещения камеры")]
|
||
public float panSpeed = 15f;
|
||
|
||
[Header("Настройки зума")]
|
||
[Tooltip("Скорость приближения/отдаления")]
|
||
public float zoomSpeed = 20f;
|
||
[Tooltip("Максимальное приближение (минимальный orthographic size)")]
|
||
public float minZoom = 2f;
|
||
[Tooltip("Максимальное отдаление (рассчитывается автоматически при старте)")]
|
||
public float maxZoom = 10f;
|
||
|
||
private Camera cam;
|
||
|
||
private void Awake()
|
||
{
|
||
cam = GetComponent<Camera>();
|
||
if (!cam.orthographic)
|
||
{
|
||
Debug.LogWarning("Камера должна быть Orthographic (ортографической) для 2D стратегии!");
|
||
cam.orthographic = true;
|
||
}
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
if (mapRenderer != null)
|
||
{
|
||
// Рассчитываем максимальное отдаление так, чтобы камера не могла стать больше самой карты
|
||
CalculateMaxZoom();
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("Не назначен mapRenderer в MapCameraController! Привяжите спрайт карты в инспекторе.");
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
HandleZoom();
|
||
HandleMovement();
|
||
}
|
||
|
||
private void CalculateMaxZoom()
|
||
{
|
||
float mapHeight = mapRenderer.bounds.size.y;
|
||
float mapWidth = mapRenderer.bounds.size.x;
|
||
|
||
// orthographicSize — это половина высоты камеры.
|
||
// Считаем максимально возможные размеры камеры, чтобы не выходить за границы карты.
|
||
float maxZoomY = mapHeight / 2f;
|
||
float maxZoomX = (mapWidth / 2f) / cam.aspect;
|
||
|
||
// Берем минимальное из двух значений, чтобы зум останавливался, когда любая из сторон карты полностью влезает в экран
|
||
maxZoom = Mathf.Min(maxZoomY, maxZoomX);
|
||
|
||
// Если текущий зум больше возможного, поправляем его
|
||
cam.orthographicSize = Mathf.Clamp(cam.orthographicSize, minZoom, maxZoom);
|
||
}
|
||
|
||
private void HandleZoom()
|
||
{
|
||
float zoomChange = 0f;
|
||
|
||
// Клавиши приближения (KeypadPlus = Num+, Equals/Plus = обычный +)
|
||
if (Input.GetKey(KeyCode.KeypadPlus) || Input.GetKey(KeyCode.Equals) || Input.GetKey(KeyCode.Plus))
|
||
{
|
||
zoomChange -= zoomSpeed * Time.deltaTime;
|
||
}
|
||
|
||
// Клавиши отдаления (KeypadMinus = Num-, Minus = обычный -)
|
||
if (Input.GetKey(KeyCode.KeypadMinus) || Input.GetKey(KeyCode.Minus))
|
||
{
|
||
zoomChange += zoomSpeed * Time.deltaTime;
|
||
}
|
||
|
||
// Также добавляем возможность зума на колесико мыши (полезно в стратегиях)
|
||
float scrollInput = Input.GetAxisRaw("Mouse ScrollWheel");
|
||
if (Mathf.Abs(scrollInput) > 0.01f)
|
||
{
|
||
zoomChange -= scrollInput * zoomSpeed * 5f; // Умножаем, так как колесико дает маленькие значения
|
||
}
|
||
|
||
if (Mathf.Abs(zoomChange) > 0.001f)
|
||
{
|
||
cam.orthographicSize = Mathf.Clamp(cam.orthographicSize + zoomChange, minZoom, maxZoom);
|
||
// Если изменился размер экрана, нужно пересчитать центрирование, что сделает функция HandleMovement
|
||
}
|
||
}
|
||
|
||
private void HandleMovement()
|
||
{
|
||
if (mapRenderer == null) return;
|
||
|
||
// Получаем ввод для осей (по умолчанию в Unity Horizontal — это A, D, LeftArrow, RightArrow; Vertical — W, S, UpArrow, DownArrow)
|
||
float horizontal = Input.GetAxisRaw("Horizontal");
|
||
float vertical = Input.GetAxisRaw("Vertical");
|
||
|
||
Vector3 moveDirection = new Vector3(horizontal, vertical, 0f).normalized;
|
||
Vector3 targetPosition = transform.position + moveDirection * panSpeed * Time.deltaTime;
|
||
|
||
// Вычисляем текущие размеры камеры
|
||
float camHalfHeight = cam.orthographicSize;
|
||
float camHalfWidth = cam.orthographicSize * cam.aspect;
|
||
|
||
Bounds mapBounds = mapRenderer.bounds;
|
||
|
||
// Вычисляем границы, за которые центр камеры не должен выходить
|
||
float minX = mapBounds.min.x + camHalfWidth;
|
||
float maxX = mapBounds.max.x - camHalfWidth;
|
||
float minY = mapBounds.min.y + camHalfHeight;
|
||
float maxY = mapBounds.max.y - camHalfHeight;
|
||
|
||
// Ограничиваем позицию по X.
|
||
// Если карта по ширине уже полностью влезает (minX > maxX), центрируем её
|
||
if (minX > maxX)
|
||
{
|
||
targetPosition.x = mapBounds.center.x;
|
||
}
|
||
else
|
||
{
|
||
targetPosition.x = Mathf.Clamp(targetPosition.x, minX, maxX);
|
||
}
|
||
|
||
// Аналогично ограничиваем по Y
|
||
if (minY > maxY)
|
||
{
|
||
targetPosition.y = mapBounds.center.y;
|
||
}
|
||
else
|
||
{
|
||
targetPosition.y = Mathf.Clamp(targetPosition.y, minY, maxY);
|
||
}
|
||
|
||
// Применяем позицию (оставляем Z как было)
|
||
targetPosition.z = transform.position.z;
|
||
transform.position = targetPosition;
|
||
}
|
||
}
|