306 lines
11 KiB
C#
306 lines
11 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using RuntimeData;
|
||
using TH1_Logic.Core;
|
||
|
||
public class CameraController : MonoBehaviour
|
||
{
|
||
public float zoomSpeed = 5f; // 滚轮缩放速度
|
||
public float minZoom = 3f; // 最小缩放值
|
||
public float maxZoom = 15f; // 最大缩放值
|
||
public float panSpeed = 0.5f; // 拖动地图的速度
|
||
|
||
|
||
//相机移动上下边界(会根据地图尺寸动态计算)
|
||
public float minX = -240f;
|
||
public float maxX = 240f;
|
||
public float minY = -80f;
|
||
public float maxY = 280f;
|
||
|
||
// 边界边距(额外留白)
|
||
public float boundaryMargin = 50f;
|
||
|
||
//相机移动动画相关参数
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据地图尺寸动态计算相机移动边界
|
||
/// </summary>
|
||
public void CalculateBoundsFromMapSize(uint mapWidth, uint mapHeight)
|
||
{
|
||
// 计算地图四个角的网格坐标对应的世界坐标
|
||
// 左下角 (0, 0)
|
||
Vector3 bottomLeft = Table.Instance.GridPosToWorld(new Vector2Int(0, 0));
|
||
// 右上角 (width-1, height-1)
|
||
Vector3 topRight = Table.Instance.GridPosToWorld(new Vector2Int((int)mapWidth - 1, (int)mapHeight - 1));
|
||
// 左上角 (0, height-1)
|
||
Vector3 topLeft = Table.Instance.GridPosToWorld(new Vector2Int(0, (int)mapHeight - 1));
|
||
// 右下角 (width-1, 0)
|
||
Vector3 bottomRight = Table.Instance.GridPosToWorld(new Vector2Int((int)mapWidth - 1, 0));
|
||
|
||
// 计算所有角的 X 和 Y 范围
|
||
float minWorldX = Mathf.Min(bottomLeft.x, topRight.x, topLeft.x, bottomRight.x);
|
||
float maxWorldX = Mathf.Max(bottomLeft.x, topRight.x, topLeft.x, bottomRight.x);
|
||
float minWorldY = Mathf.Min(bottomLeft.y, topRight.y, topLeft.y, bottomRight.y);
|
||
float maxWorldY = Mathf.Max(bottomLeft.y, topRight.y, topLeft.y, bottomRight.y);
|
||
|
||
// 添加边距
|
||
minX = minWorldX - boundaryMargin;
|
||
maxX = maxWorldX + boundaryMargin;
|
||
minY = minWorldY - boundaryMargin;
|
||
maxY = maxWorldY + boundaryMargin;
|
||
|
||
Debug.Log($"Camera bounds calculated: X[{minX}, {maxX}], Y[{minY}, {maxY}] for map size {mapWidth}x{mapHeight}");
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
HandleSmoothMove();
|
||
HandleZoom();
|
||
if (Screen.width != _lastWidth || Screen.height != _lastHeight)
|
||
UpdateViewport();
|
||
//if (_camera.orthographic) _camera.orthographicSize = 20f;
|
||
}
|
||
|
||
private void LateUpdate()
|
||
{
|
||
HandlePan();
|
||
}
|
||
|
||
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 (!UIBlockCameraDrag.MoveEvent && _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;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CancelSmoothMove()
|
||
{
|
||
_smoothTargetPosition = null;
|
||
_isMoving = false;
|
||
_moveProgress = 0f;
|
||
}
|
||
|
||
|
||
void HandleZoom()
|
||
{
|
||
// 鼠标不在地图可交互区域时不响应滚轮缩放;ShouldBlockDrag 兜住正在拖动地图、鼠标暂时滑到UI上的情况
|
||
if (!UIBlockCameraDrag.IsPointerOnUI && !UIBlockCameraDrag.ShouldBlockDrag) return;
|
||
|
||
// 获取滚轮输入
|
||
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 CameraMove(Vector3 deltaVector)
|
||
{
|
||
Vector3 targetPosition = Camera.main.transform.position + deltaVector;
|
||
|
||
// 计算当前相机视野的一半宽高
|
||
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;
|
||
}
|
||
void HandlePan()
|
||
{
|
||
if (UIBlockCameraDrag.MoveEvent)
|
||
{
|
||
CancelSmoothMove();
|
||
CameraMove(UIBlockCameraDrag.MoveVector);
|
||
/*Vector3 targetPosition = Camera.main.transform.position + ;
|
||
|
||
// 计算当前相机视野的一半宽高
|
||
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;*/
|
||
UIBlockCameraDrag.DragOrigin = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||
return;
|
||
}
|
||
|
||
var main = Main.Instance;
|
||
var inputLogic = main != null ? main.InputLogic : null;
|
||
if (inputLogic != null && inputLogic.WASDMapMover)
|
||
{
|
||
inputLogic.WASDMapMover = false;
|
||
CameraMove(inputLogic.WASDMapMoverVector);
|
||
}
|
||
}
|
||
|
||
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 = 1400f;
|
||
float boxHeight = 600f;
|
||
|
||
// 削减左侧150像素后的区域
|
||
float reducedLeft = 550f;
|
||
|
||
//如果是AI行动,给画面中心位置
|
||
if (!Main.MapData.CurPlayer?.IsSelfPlayer() ?? false)
|
||
{
|
||
boxWidth = 400f;
|
||
boxHeight = 200f;
|
||
reducedLeft = 0f;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
}
|