TH1/Unity/Assets/Scripts/UI/CameraController.cs
2025-07-17 18:26:28 +08:00

226 lines
7.7 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using RuntimeData;
public class CameraController : MonoBehaviour
{
public float zoomSpeed = 5f; // 滚轮缩放速度
public float minZoom = 3f; // 最小缩放值
public float maxZoom = 15f; // 最大缩放值
public float panSpeed = 0.5f; // 拖动地图的速度
//相机拖动相关参数
private Vector3 _dragOrigin; // 记录拖动起点
//相机移动上下边界
public float minX = -200f;
public float maxX = 200f;
public float minY = -60f;
public float maxY = 230f;
//相机移动动画相关参数
public float moveSpeed = 0.5f; // 平滑移动速度
private Vector3? _smoothTargetPosition = null; //记录相机平滑移动的起点
private Vector3 _startPos;
private float _moveProgress = 0f;
private float _moveDuration; // 可调节移动总时长
private bool _isMoving = false;
private const float TARGET_ASPECT = 16f / 9f; // 目标宽高比
private Camera _camera;
private int _lastWidth, _lastHeight;
void Start()
{
_camera = GetComponent<Camera>();
UpdateViewport();
}
void Update()
{
if (UIBlockCameraDrag.ShouldBlockDrag || UIBlockCameraDrag.IsPointerOnUI ) return;
HandleSmoothMove();
HandleZoom();
HandlePan();
if (Screen.width != _lastWidth || Screen.height != _lastHeight)
UpdateViewport();
if (_camera.orthographic) _camera.orthographicSize = 20f;
}
void UpdateViewport()
{
float currentAspect = (float)Screen.width / Screen.height;
Rect rect = new Rect(0, 0, 1, 1); // 默认全屏
if (currentAspect > TARGET_ASPECT)
{
// 窗口过宽:左右黑边
rect.width = TARGET_ASPECT / currentAspect;
rect.x = (1f - rect.width) / 2f;
}
else if (currentAspect < TARGET_ASPECT)
{
// 窗口过高:上下黑边
rect.height = currentAspect / TARGET_ASPECT;
rect.y = (1f - rect.height) / 2f;
}
_camera.rect = rect; // 应用视口矩形
_lastWidth = Screen.width;
_lastHeight = Screen.height;
}
void HandleSmoothMove()
{
if (_isMoving && _smoothTargetPosition.HasValue)
{
_moveProgress += Time.deltaTime / _moveDuration;
float t = Mathf.SmoothStep(0, 1, _moveProgress); // 缓动曲线
Vector3 targetPos = _smoothTargetPosition.Value;
Camera.main.transform.position = Vector3.Lerp(_startPos, targetPos, t);
if (_moveProgress >= 1f)
{
Camera.main.transform.position = targetPos;
_smoothTargetPosition = null;
_isMoving = false;
}
}
}
void HandleZoom()
{
// 获取滚轮输入
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll != 0f)
{
Camera.main.orthographicSize -= scroll * zoomSpeed;
Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize, minZoom, maxZoom);
}
}
void HandlePan()
{
if (Input.GetMouseButtonDown(0))
{
_dragOrigin = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (Input.GetMouseButton(0))
{
Vector3 difference = _dragOrigin - Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 targetPosition = Camera.main.transform.position + difference;
// 计算当前相机视野的一半宽高
float vertExtent = Camera.main.orthographicSize;
float horzExtent = vertExtent * Camera.main.aspect;
// 限制相机的中心点,使得视野边缘不超出边界
float minXClamp = minX + horzExtent;
float maxXClamp = maxX - horzExtent;
float minYClamp = minY + vertExtent;
float maxYClamp = maxY - vertExtent;
targetPosition.x = Mathf.Clamp(targetPosition.x, minXClamp, maxXClamp);
targetPosition.y = Mathf.Clamp(targetPosition.y, minYClamp, maxYClamp);
Camera.main.transform.position = targetPosition;
}
}
public void CameraFocusOnGrid(GridData gridData, bool Center = false)
{
Vector3 worldPosition = Table.Instance.GridToWorld(gridData);
float vertExtent = Camera.main.orthographicSize;
float horzExtent = vertExtent * Camera.main.aspect;
_moveDuration = Table.Instance.AnimDataAssets.AIAnimCameraMoveTime;
//瞬间移到中心
if (Center)
{
float clampedX = Mathf.Clamp(worldPosition.x, minX + horzExtent, maxX - horzExtent);
float clampedY = Mathf.Clamp(worldPosition.y, minY + vertExtent, maxY - vertExtent);
Vector3 finalTarget = new Vector3(clampedX, clampedY, Camera.main.transform.position.z);
_startPos = Camera.main.transform.position;
_smoothTargetPosition = finalTarget;
_moveProgress = 0f;
_isMoving = true;
}
//平滑移动到视觉框内
else
{
Vector3 camPos = Camera.main.transform.position;
// 获取世界坐标 → 屏幕坐标
Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPosition);
float screenWidth = Screen.width;
float screenHeight = Screen.height;
// 原始区域尺寸
float boxWidth = 800f;
float boxHeight = 500f;
// 削减左侧150像素后的区域
float reducedLeft = 200f;
float adjustedBoxWidth = boxWidth - reducedLeft;
float xMax = (screenWidth + boxWidth) / 2f; // 保持右侧不变
float xMin = xMax - adjustedBoxWidth; // 左侧往右收缩150像素
float yMin = (screenHeight - boxHeight) / 2f;
float yMax = (screenHeight + boxHeight) / 2f;
// 如果点已经在框中,不动
if (screenPos.x >= xMin && screenPos.x <= xMax &&
screenPos.y >= yMin && screenPos.y <= yMax)
{
return;
}
// 计算目标点应该在屏幕中央框内的“目标屏幕位置”
float targetScreenX = Mathf.Clamp(screenPos.x, xMin, xMax);
float targetScreenY = Mathf.Clamp(screenPos.y, yMin, yMax);
Vector3 desiredScreenPos = new Vector3(targetScreenX, targetScreenY, screenPos.z);
// 将这个屏幕位置转回世界空间
Vector3 desiredWorldPos = Camera.main.ScreenToWorldPoint(desiredScreenPos);
// 计算需要相机移动的 delta = 当前格子位置 - 应该出现在的位置
Vector3 offset = worldPosition - desiredWorldPos;
Vector3 targetPos = camPos + offset;
// 限制相机移动范围
vertExtent = Camera.main.orthographicSize;
horzExtent = vertExtent * Camera.main.aspect;
float minXClamp = minX + horzExtent;
float maxXClamp = maxX - horzExtent;
float minYClamp = minY + vertExtent;
float maxYClamp = maxY - vertExtent;
targetPos.x = Mathf.Clamp(targetPos.x, minXClamp, maxXClamp);
targetPos.y = Mathf.Clamp(targetPos.y, minYClamp, maxYClamp);
// 平滑移动
_startPos = camPos;
_smoothTargetPosition = new Vector3(targetPos.x, targetPos.y, camPos.z);
_moveProgress = 0f;
_isMoving = true;
}
}
}