using System; using DG.Tweening; using Framework; using GameWrapper; using Gameplay.Guide; using UnityEngine; using UnityEngine.EventSystems; namespace Gameplay { /// /// 相机逻辑的具体实现,实现ICameraLogic接口 /// public class CameraLogic : ICameraLogic { private CameraData cameraData; // 内部状态变量 private float targetZoomScale; private float zoomVelocity; private Vector3 targetPanPosition; private Vector3 panVelocity; private Vector2 lastDragDelta; private float lastDragTime; private Vector3 _startPos; private float _cacheZoomScale; private bool isIgnoreZoomLimit; // 缩放百分比,0表示放到最小,1表示放到最大 private float ZoomScale { get { if (cameraData.IsOrthographic) return (cameraData.CameraMaxSize - cameraData.MainCamera.orthographicSize) / (cameraData.CameraMaxSize - cameraData.CameraMinSize); else return (cameraData.CameraMaxFOV - cameraData.MainCamera.fieldOfView) / (cameraData.CameraMaxFOV - cameraData.CameraMinFOV); } set { var t = Mathf.Clamp(value, 0, 1); if (Math.Abs(ZoomScale - t) < float.Epsilon) return; if (cameraData.IsOrthographic) cameraData.MainCamera.orthographicSize = Mathf.Lerp(cameraData.CameraMaxSize, cameraData.CameraMinSize, t); else cameraData.MainCamera.fieldOfView = Mathf.Lerp(cameraData.CameraMaxFOV, cameraData.CameraMinFOV, t); } } //size,将透视和正交相机的fov和orthographic size整合为统一数值 private float Size { get { if (cameraData.IsOrthographic) return cameraData.MainCamera.orthographicSize; else { var fov = cameraData.MainCamera.fieldOfView; //这里乘(CameraMaxSize - CameraMinSize)/(CameraMaxFOV - CameraMinFOV)是将fov的区间变得和orthographic size区间一致 return fov * (cameraData.CameraMaxSize - cameraData.CameraMinSize) / (cameraData.CameraMaxFOV - cameraData.CameraMinFOV); } } } public CameraLogic(CameraData cameraData) { this.cameraData = cameraData; targetZoomScale = ZoomScale; targetPanPosition = cameraData.transform.position; } /// /// 注册工厂方法,在Unity初始化时调用 /// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void RegisterFactory() { CameraLogicFactory.RegisterFactory(data => new CameraLogic(data)); Debug.Log("Registered CameraLogic factory method"); } public void Initialize() { if (Application.isPlaying) { EventManager.Instance.Register(EventManager.EventName.Level_OnDrag, OnDragMove); EventManager.Instance.Register(EventManager.EventName.Level_OnEndDrag, OnEndDrag); InputManager.Instance.OnFingersMove += OnFingersMove; } } public void Cleanup() { if (Application.isPlaying) { if (InputManager.Instance == null) return; EventManager.Instance.Unregister(EventManager.EventName.Level_OnDrag, OnDragMove); EventManager.Instance.Unregister(EventManager.EventName.Level_OnEndDrag, OnEndDrag); InputManager.Instance.OnFingersMove -= OnFingersMove; } } public void Update() { // 处理平滑缩放 if (cameraData.smoothZoom && Math.Abs(ZoomScale - targetZoomScale) > 0.001f) { // 使用SmoothDamp实现平滑缩放效果 float newZoomScale = Mathf.SmoothDamp(ZoomScale, targetZoomScale, ref zoomVelocity, cameraData.zoomSmoothTime); ZoomScale = newZoomScale; AdjustSelf(); } // 处理平滑平移 if (cameraData.smoothPanning && Vector3.Distance(cameraData.transform.position, targetPanPosition) > 0.01f) { // 限制最大速度 Vector3 newPosition = Vector3.SmoothDamp(cameraData.transform.position, targetPanPosition, ref panVelocity, cameraData.panSmoothTime, cameraData.maxPanSpeed); cameraData.transform.position = newPosition; AdjustSelf(); } } private void OnDragMove(PointerEventData pointerData) { if (!cameraData.FingerMoveEnable) return; Vector3 newPosition; var startPos = pointerData.pressPosition; var delta = pointerData.delta; // 记录拖动速度数据,用于惯性计算 lastDragDelta = delta; lastDragTime = Time.time; var oldRay = cameraData.MainCamera.ScreenPointToRay(startPos); var newRay = cameraData.MainCamera.ScreenPointToRay(startPos + delta); var layerMask = 1 << LayerMask.NameToLayer("Ground"); if (Physics.Raycast(oldRay, out var oldHit, 1000, layerMask) && Physics.Raycast(newRay, out var newHit, 1000, layerMask)) { var offset = oldHit.point - newHit.point; if (cameraData.smoothPanning) { // 在平滑模式下设置目标位置 targetPanPosition = cameraData.transform.position + offset; } else { // 立即移动 cameraData.transform.Translate(offset, Space.World); AdjustSelf(); } } else { Vector2 touchDeltaPosition = -delta; float ratio = Size * cameraData.unitPerPixel; Vector2 cameraMove = new(touchDeltaPosition.x * cameraData.moveSpeedX * ratio, touchDeltaPosition.y * cameraData.moveSpeedY * ratio); var cameraTransform = cameraData.transform; var moveY = cameraTransform.up; moveY.y = 0; moveY = moveY.normalized * cameraMove.y; var moveX = cameraTransform.right; moveX.y = 0; moveX = moveX.normalized * cameraMove.x; if (cameraData.smoothPanning) { // 在平滑模式下设置目标位置 targetPanPosition = cameraData.transform.position + moveX + moveY; } else { // 立即移动 cameraData.transform.Translate(moveX + moveY, Space.World); AdjustSelf(); } } } public void OnEndDrag(PointerEventData pointerData) { if (cameraData.smoothPanning && cameraData.panInertia > 0 && Time.time - lastDragTime < 0.1f) { // 计算惯性位移 Vector2 touchDeltaPosition = -lastDragDelta * cameraData.panInertia; float ratio = Size * cameraData.unitPerPixel; Vector2 inertiaMove = new(touchDeltaPosition.x * cameraData.moveSpeedX * ratio, touchDeltaPosition.y * cameraData.moveSpeedY * ratio); var cameraTransform = cameraData.transform; var moveY = cameraTransform.up; moveY.y = 0; moveY = moveY.normalized * inertiaMove.y; var moveX = cameraTransform.right; moveX.y = 0; moveX = moveX.normalized * inertiaMove.x; // 应用惯性 targetPanPosition += moveX + moveY; } } private void OnFingersMove(float delta) { if (!cameraData.FingerMoveEnable) { return; } if (GuideManager.Instance.IsGuiding) // 引导中禁止缩放 return; // 缩放系数随当前缩放程度变化,缩放越小,缩放速度越慢,提供更精确的控制 float currentZoomFactor = CameraData.ZoomStep * cameraData.zoomSensitivity; // 根据当前缩放比例调整缩放速度 if (cameraData.zoomScaleFactor > 0) { float scaleModifier = Mathf.Lerp(0.5f, 1.5f, ZoomScale * cameraData.zoomScaleFactor); currentZoomFactor *= scaleModifier; } //delta小于0是缩小 var zoomDelta = delta < 0 ? -currentZoomFactor : currentZoomFactor; //修改目标缩放值 if (cameraData.smoothZoom) { targetZoomScale = Mathf.Clamp01(targetZoomScale + zoomDelta); } else { //直接缩放,无平滑效果 ZoomScale += zoomDelta; AdjustSelf(); } } public void AdjustSelf() { cameraData.transform.position = AdjustPosition(Size, out var isInsideBounds); } private Vector3 AdjustPosition(float size, out bool IsInsideBounds) { var position = cameraData.transform.position; IsInsideBounds = true; var center = cameraData.CalculateHitHorizontalPosition(position, cameraData.transform.forward, 0); var left = center.x - cameraData.leftMargin * size; var right = center.x + cameraData.rightMargin * size; var top = center.z + cameraData.topMargin * size; var bottom = center.z - cameraData.bottomMargin * size; if (right - left < cameraData.CameraBounds.max.x - cameraData.CameraBounds.min.x) { if (left < cameraData.CameraBounds.min.x) { center.x = cameraData.CameraBounds.min.x + cameraData.leftMargin * size; IsInsideBounds = false; } else if (right > cameraData.CameraBounds.max.x) { center.x = cameraData.CameraBounds.max.x - cameraData.rightMargin * size; IsInsideBounds = false; } } else { center.x = cameraData.CameraBounds.center.x; IsInsideBounds = false; } if (top - bottom < cameraData.CameraBounds.max.z - cameraData.CameraBounds.min.z) { if (bottom < cameraData.CameraBounds.min.z) { center.z = cameraData.CameraBounds.min.z + cameraData.bottomMargin * size; IsInsideBounds = false; } else if (top > cameraData.CameraBounds.max.z) { center.z = cameraData.CameraBounds.max.z - cameraData.topMargin * size; IsInsideBounds = false; } } else { center.z = cameraData.CameraBounds.center.z; IsInsideBounds = false; } position = cameraData.CalculateHitHorizontalPosition(center, cameraData.transform.forward, position.y); return position; } public void KeepCenter(Vector3 centerPos) { var cacheTrans = cameraData.MainCamera.transform; var oldPos = cacheTrans.position; oldPos.x = centerPos.x - 5f; oldPos.z = centerPos.z - 25f; cacheTrans.DOMove(oldPos, 0.3f).OnUpdate(AdjustSelf); } /// /// 营地相机保持中心位置 /// /// public void CampKeepCenter(Vector3 centerPos) { Transform cacheTrans = cameraData.MainCamera.transform; Vector3 newPos = cacheTrans.position; newPos.x = centerPos.x + 17.5f; newPos.z = centerPos.z + 30.5f; cacheTrans.DOMove(newPos, 0.3f).OnUpdate(AdjustSelf).OnComplete(() => { targetZoomScale = 1f; }); } public void RecordStartPos() { _startPos = cameraData.MainCamera.transform.position; _cacheZoomScale = targetZoomScale; } public void ResetToStartPos(float during = 0.3f) { if (cameraData.MainCamera == null) return; targetZoomScale = _cacheZoomScale; cameraData.MainCamera.transform.DOMove(_startPos, during).OnUpdate(AdjustSelf); } private Vector3 CalculateCell2CameraPosition(Vector3 targetPosition) { var cameraTransform = cameraData.MainCamera.transform; var startPosition = cameraTransform.position; var v = cameraTransform.forward; float x, z; z = targetPosition.z - v.z * (targetPosition.y - startPosition.y) / v.y; x = targetPosition.x - v.x * (targetPosition.y - startPosition.y) / v.y; return new Vector3(x, startPosition.y, z); } public void InitializeCameraPosition(Vector3 targetPosition, CameraInfoData cameraInfo = null) { cameraData.MainCamera.transform.position = CalculateCell2CameraPosition(targetPosition); // 进入关卡初始化相机 if (cameraInfo != null) { cameraData.rightMargin = cameraInfo.rightMarginInPre; cameraData.leftMargin = cameraInfo.leftMarginInPre; cameraData.topMargin = cameraInfo.topMarginInInPre; cameraData.bottomMargin = cameraInfo.bottomMarginInPre; SetCameraFOVSize(cameraInfo.initialFOV); } var rotEuler = cameraData.UseOrthographicMode ? cameraData.CameraStartRotationO : cameraData.CameraStartRotationP; AdjustSelf(); } public void SetCameraFOVSize(float initialFOV) { if (cameraData.MainCamera == null) return; var fov = Mathf.Clamp(initialFOV, cameraData.CameraMinFOV, cameraData.CameraMaxFOV); if (!cameraData.IsOrthographic) { cameraData.CameraStartFOV = fov; cameraData.MainCamera.fieldOfView = fov; targetZoomScale = ZoomScale; } } } }