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

1 line
11 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 Framework;
using Gameplay.Performance;
using UnityEngine;
using Sirenix.OdinInspector;
[ExecuteAlways]
public class CameraController : MonoBehaviour
{
private const float CameraStartY = 25;
private const float CameraStartSize = 12;
private const float CameraStartFOV = 30;
private const float NearClipPlane = 0.03f;
private const float FarClipPlane = 150;
private readonly Vector3 cameraStartRotationO = new Vector3(37.5f, -10f, 0f);
private readonly Vector3 cameraStartRotationP = new Vector3(45, -10, 0);
//之前的缩放是6次滚轮从最小放到最大故每一次缩放的值为1/6f
private const float ZoomStep = 1 / 12f;
public float leftMargin = 1.5f;
public float rightMargin = 1.5f;
public float topMargin = 0.9f;
public float bottomMargin = 0.9f;
public float moveSpeedX = 0.19f;
public float moveSpeedY = 0.3f;
public float unitPerPixel = 0.01f;
[ShowIf("isFightCamera")] public float CameraMinSize = 6;
[ShowIf("isFightCamera")] public float CameraMaxSize = 12;
[HideIf("isFightCamera")] public BoxCollider boxBounds;
[HideIf("isFightCamera")] public float CameraMinFOV = 15;
[HideIf("isFightCamera")] public float CameraMaxFOV = 30;
[LabelText("是否战斗相机")] public bool isFightCamera = true;
private Camera mainCamera;
private bool isIgnoreZoomLimit;
public Bounds CameraBounds { get; set; }
private bool isOrthographic => mainCamera.orthographic;
//Camera拖动控制
public static bool FingerMoveEnable = true;
//size,将透视和正交相机的fov和orthographic size整合为统一数值
private float Size
{
get
{
if (isOrthographic)
return mainCamera.orthographicSize;
else
{
var fov = mainCamera.fieldOfView;
//这里乘(CameraMaxSize - CameraMinSize)/(CameraMaxFOV - CameraMinFOV)是将fov的区间变得和orthographic size区间一致
return fov * (CameraMaxSize - CameraMinSize) / (CameraMaxFOV - CameraMinFOV);
}
}
}
//缩放百分比0表示放到最小1表示放到最大
private float ZoomScale
{
get
{
if (isOrthographic)
return (CameraMaxSize - mainCamera.orthographicSize) / (CameraMaxSize - CameraMinSize);
else
return (CameraMaxFOV - mainCamera.fieldOfView) / (CameraMaxFOV - CameraMinFOV);
}
set
{
var t = Mathf.Clamp(value, 0, 1);
if (Math.Abs(ZoomScale - t) < float.Epsilon)
return;
if (isOrthographic)
mainCamera.orthographicSize = Mathf.Lerp(CameraMaxSize, CameraMinSize, t);
else
mainCamera.fieldOfView = Mathf.Lerp(CameraMaxFOV, CameraMinFOV, t);
}
}
private void Awake()
{
mainCamera = GetComponent<Camera>();
if (isFightCamera)
{
var useOrthographic = PerformanceManager.instance != null &&
PerformanceManager.instance.data.fightUseOrthographic;
var rotEuler = useOrthographic ? cameraStartRotationO : cameraStartRotationP;
if (useOrthographic)
{
// TODO: 这里的值是固定的,需要根据实际情况调整
//bottomMargin = 0.9f;
mainCamera.orthographic = true;
mainCamera.orthographicSize = CameraStartSize;
mainCamera.transform.SetPositionAndRotation(new Vector3(0, CameraStartY, 0),
Quaternion.Euler(rotEuler));
}
else
{
// TODO: 这里的值是固定的,需要根据实际情况调整
//bottomMargin = 0.7f;
mainCamera.orthographic = false;
mainCamera.fieldOfView = 30;
mainCamera.transform.SetPositionAndRotation(new Vector3(0, 27, 0),
Quaternion.Euler(rotEuler));
}
}
mainCamera.nearClipPlane = NearClipPlane;
mainCamera.farClipPlane = FarClipPlane;
CameraBounds = boxBounds != null ? boxBounds.bounds : CameraBounds;
AdjustSelf();
}
private void OnEnable()
{
if (Application.isPlaying)
{
//InputManager.Instance.OnFingerMove += OnFingerMove2;
EventManager.Instance.Register(EventManager.EventName.Level_OnDrag, (Action<Vector2>) OnFingerMove2);
InputManager.Instance.OnFingersMove += OnFingersMove;
}
}
private void OnDisable()
{
if (Application.isPlaying)
{
if (InputManager.Instance == null) return;
//InputManager.Instance.OnFingerMove -= OnFingerMove2;
EventManager.Instance.Register(EventManager.EventName.Level_OnDrag, (Action<Vector2>) OnFingerMove2);
InputManager.Instance.OnFingersMove -= OnFingersMove;
}
}
private void OnFingerMove2(Vector2 delta)
{
if (!FingerMoveEnable)
return;
Vector2 touchDeltaPosition = -delta;
float ratio = Size * unitPerPixel;
Vector2 cameraMove = new(touchDeltaPosition.x * moveSpeedX * ratio, touchDeltaPosition.y * moveSpeedY * ratio);
var cameraTransform = 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;
transform.Translate(moveX + moveY, Space.World);
AdjustSelf();
}
private void OnFingersMove(float delta)
{
if (!FingerMoveEnable)
{
return;
}
//delta小于0是缩小
var zoomDelta = delta < 0 ? -ZoomStep : ZoomStep;
//修改缩放值
ZoomScale += zoomDelta;
AdjustSelf();
}
Vector3 CalculateHitHorizontalPosition(Vector3 startPosition, Vector3 dir, float y)
{
if (dir.y == 0)
return Vector3.zero;
var p1 = startPosition; // 直线上一点
var v = dir; // 直线的方向向量
float x, z;
// 已知直线上一点 p1(x1, y1, z1) 和 直线的方向向量 v(m, n, p)
// 根据点向式
// (x - x1) / m = (y - y1) / n = (z - z1) / p
// 有:
// (x - p1.x) / v.x = (y - p1.y) / v.y = (z - p1.z) / v.z
// 有:
// x = p1.x + v.x * (y - p1.y) / v.y
// z = p1.z + v.z * (y - p1.y) / v.y
// 与平面 y = y 的交点坐标为
x = p1.x + v.x * (y - p1.y) / v.y;
z = p1.z + v.z * (y - p1.y) / v.y;
return new Vector3(x, y, z);
}
public void InitializeCameraPosition(Vector3 targetPosition)
{
var useOrthographic =
PerformanceManager.instance != null && PerformanceManager.instance.data.fightUseOrthographic;
var rotEuler = useOrthographic ? cameraStartRotationO : cameraStartRotationP;
mainCamera.transform.SetPositionAndRotation(
CalculateCell2CameraPosition(targetPosition), Quaternion.Euler(rotEuler));
AdjustSelf();
}
private Vector3 CalculateCell2CameraPosition(Vector3 targetPosition)
{
var cameraTransform = 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 AdjustSelf()
{
mainCamera.transform.position = AdjustPosition(Size, out var isInsideBounds);
}
private Vector3 AdjustPosition(float size, out bool IsInsideBounds)
{
var position = transform.position;
IsInsideBounds = true;
var center = CalculateHitHorizontalPosition(position, transform.forward, 0);
var left = center.x - leftMargin * size;
var right = center.x + rightMargin * size;
var top = center.z + topMargin * size;
var bottom = center.z - bottomMargin * size;
if (right - left < CameraBounds.max.x - CameraBounds.min.x)
{
if (left < CameraBounds.min.x)
{
center.x = CameraBounds.min.x + leftMargin * size;
IsInsideBounds = false;
}
else if (right > CameraBounds.max.x)
{
center.x = CameraBounds.max.x - rightMargin * size;
IsInsideBounds = false;
}
}
else
{
center.x = CameraBounds.center.x;
IsInsideBounds = false;
}
if (top - bottom < CameraBounds.max.z - CameraBounds.min.z)
{
if (bottom < CameraBounds.min.z)
{
center.z = CameraBounds.min.z + bottomMargin * size;
IsInsideBounds = false;
}
else if (top > CameraBounds.max.z)
{
center.z = CameraBounds.max.z - topMargin * size;
IsInsideBounds = false;
}
}
else
{
center.z = CameraBounds.center.z;
IsInsideBounds = false;
}
position = CalculateHitHorizontalPosition(center, transform.forward, position.y);
return position;
}
private void OnDrawGizmos()
{
if (mainCamera != null)
{
Gizmos.color = Color.red;
var cameraTransform = transform;
var position = cameraTransform.position;
var size = Size;
var center = CalculateHitHorizontalPosition(position, cameraTransform.forward, 0);
var left = center.x - leftMargin * size;
var right = center.x + rightMargin * size;
var top = center.z + topMargin * size;
var bottom = center.z - bottomMargin * size;
Gizmos.DrawLineList(new ReadOnlySpan<Vector3>(new[]
{
new Vector3(left, 0.5f, top), new Vector3(left, 0.5f, bottom),
new Vector3(left, 0.5f, bottom), new Vector3(right, 0.5f, bottom),
new Vector3(right, 0.5f, bottom), new Vector3(right, 0.5f, top),
new Vector3(right, 0.5f, top), new Vector3(left, 0.5f, top),
}
)
);
CameraBounds = boxBounds == null ? CameraBounds : boxBounds.bounds;
Gizmos.DrawWireCube(CameraBounds.center, CameraBounds.size);
}
}
}