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

1 line
8.6 KiB
C#

using Gameplay;
using System;
using UnityEngine;
[ExecuteAlways]
public class CameraController : MonoBehaviour
{
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;
public int CameraMinSize = 6;
public int CameraMaxSize = 12;
private const int CameraStartY = 25;
private Vector3 cameraStartRotation = new Vector3(37.5f, -10f, 0f);
private Vector3 cameraDefaultRotation = new Vector3(90, 0, 0);
public const int CameraStartSize = 6;
private const float NearClipPlane = 0.03f;
private const float FarClipPlane = 60;
private const bool IsOrthographic = true;
private Camera mainCamera;
private bool isIgnoreZoomLimit;
public Map Map
{
get => map;
set { map = value; }
}
private Map map;
private void Awake()
{
mainCamera = GetComponent<Camera>();
mainCamera.transform.SetPositionAndRotation(new Vector3(0, CameraStartY, 0),
Quaternion.Euler(cameraStartRotation));
mainCamera.orthographic = IsOrthographic;
mainCamera.orthographicSize = CameraStartSize;
mainCamera.nearClipPlane = NearClipPlane;
mainCamera.farClipPlane = FarClipPlane;
var endPosition = AdjustPosition(mainCamera.orthographicSize, out var canZoom);
mainCamera.transform.position = endPosition;
}
private void OnEnable()
{
if (Application.isPlaying)
{
InputManager.Instance.OnFingerMove += OnFingerMove2;
InputManager.Instance.OnFingersMove += OnFingersMove;
}
}
private void OnDisable()
{
if (Application.isPlaying)
{
InputManager.Instance.OnFingerMove -= OnFingerMove2;
InputManager.Instance.OnFingersMove -= OnFingersMove;
}
}
private void OnFingerMove2(Vector2 delta)
{
var touchDeltaPosition = -delta;
var ratio = mainCamera.orthographicSize * unitPerPixel;
var cameraMove = new Vector2(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);
var endPosition = AdjustPosition(mainCamera.orthographicSize, out var canZoom);
mainCamera.transform.position = endPosition;
}
private void OnFingersMove(float delta)
{
if (delta < 0)
{
var endPosition = AdjustPosition(mainCamera.orthographicSize + 1, out var canZoom);
if ((canZoom && mainCamera.orthographicSize < CameraMaxSize) || isIgnoreZoomLimit)
{
mainCamera.orthographicSize++;
mainCamera.transform.position = endPosition;
}
}
else
{
if (mainCamera.orthographicSize > CameraMinSize)
{
mainCamera.orthographicSize--;
}
}
}
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(Vector2Int targetPosition)
{
var cellPos = map.BlockPosition2WorldPosition(targetPosition);
mainCamera.transform.SetPositionAndRotation(
CalculateCell2CameraPosition(cellPos), Quaternion.Euler(cameraStartRotation));
mainCamera.transform.position = AdjustPosition(mainCamera.orthographicSize, out var canZoom);
}
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);
}
private Vector3 AdjustPosition(float size, out bool canZoom)
{
var position = transform.position;
if (map?.TerrainGridSystem == null)
{
canZoom = false;
return position;
}
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;
var mapBounds = map.TerrainGridSystem.bounds;
if (left < mapBounds.min.x)
{
center.x = mapBounds.min.x + leftMargin * size;
canZoom = false;
//DebugUtil.LogG($"left < mapBounds.min.x, {left} < {mapBounds.min.x}");
}
else if (right > mapBounds.max.x)
{
center.x = mapBounds.max.x - rightMargin * size;
//DebugUtil.LogG($"right > mapBounds.max.x, {right} > {mapBounds.max.x}");
canZoom = false;
}
if (bottom < mapBounds.min.z)
{
center.z = mapBounds.min.z + bottomMargin * size;
//DebugUtil.LogG($"bottom < mapBounds.min.x, {bottom} < {mapBounds.min.x}");
canZoom = false;
}
else if (top > mapBounds.max.z)
{
center.z = mapBounds.max.z - topMargin * size;
//DebugUtil.LogG($"top > mapBounds.max.x, {top} > {mapBounds.max.x}");
canZoom = false;
}
position = CalculateHitHorizontalPosition(center, transform.forward, position.y);
canZoom = true;
return position;
}
public void SwitchCameraView(bool isGameView)
{
if (!isGameView)
{
isIgnoreZoomLimit = true;
mainCamera.transform.SetPositionAndRotation(new Vector3(0, CameraStartY, 0),
Quaternion.Euler(cameraDefaultRotation));
}
else
{
isIgnoreZoomLimit = false;
mainCamera.transform.SetPositionAndRotation(new Vector3(0, CameraStartY, 0),
Quaternion.Euler(cameraStartRotation));
}
mainCamera.orthographicSize = CameraMaxSize;
mainCamera.nearClipPlane = NearClipPlane;
mainCamera.farClipPlane = FarClipPlane;
var endPosition = AdjustPosition(mainCamera.orthographicSize, out var canZoom);
mainCamera.transform.position = endPosition;
}
private void OnDrawGizmos()
{
if (map != null && mainCamera != null)
{
Gizmos.color = Color.red;
var cameraTransform = transform;
var position = cameraTransform.position;
var size = mainCamera.orthographicSize;
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),
}
)
);
var mapBounds = map.TerrainGridSystem.bounds;
Gizmos.DrawWireCube(mapBounds.center, mapBounds.size);
}
}
}