NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Camera/CameraLogic.cs

388 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using DG.Tweening;
using Framework;
using GameWrapper;
using Gameplay.Guide;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Gameplay
{
/// <summary>
/// 相机逻辑的具体实现实现ICameraLogic接口
/// </summary>
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;
}
/// <summary>
/// 注册工厂方法在Unity初始化时调用
/// </summary>
[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<PointerEventData>(EventManager.EventName.Level_OnDrag, OnDragMove);
EventManager.Instance.Register<PointerEventData>(EventManager.EventName.Level_OnEndDrag, OnEndDrag);
InputManager.Instance.OnFingersMove += OnFingersMove;
}
}
public void Cleanup()
{
if (Application.isPlaying)
{
if (InputManager.Instance == null) return;
EventManager.Instance.Unregister<PointerEventData>(EventManager.EventName.Level_OnDrag, OnDragMove);
EventManager.Instance.Unregister<PointerEventData>(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);
}
/// <summary>
/// 营地相机保持中心位置
/// </summary>
/// <param name="centerPos"></param>
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;
}
}
}
}