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(); UpdateViewport(); } /// /// 根据地图尺寸动态计算相机移动边界 /// 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; } } } 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) { 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); } else if (Main.Instance.InputLogic!= null && Main.Instance.InputLogic.WASDMapMover) { Main.Instance.InputLogic.WASDMapMover = false; CameraMove(Main.Instance.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; } } }