Unity相机环绕,移动,缩放脚本
环绕限制高低
缩放限制大小
unity结构示意图
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class FXCameraControl : MonoBehaviour
{
private const string MOUSESCROLLWHEEL = "Mouse ScrollWheel"; // 鼠标滚轮.
private const string MOUSEX = "Mouse X";
private const string MOUSEY = "Mouse Y";
[Header("---------------基础---------------")]
public bool isDrawGizmos = true;
public Transform operatingTrn; //操作点
public Transform cameraTrn; //相机
public CamModel camModel = CamModel.WorldRoaming;
[Header("-----世界漫游-----")]
public float SJ_Zoom_Min = 2f;
public float SJ_Zoom_Max = 30f;
[Header("-----作业面视角-----")]
public float ZYM_Zoom_Min = 6f;
public float ZYM_Zoom_Max = 18f;
public float ZYM_Radius = 5f; //作业面半径
[Header("---------------缩放---------------")]
public float currentZoomDistance; //初始距离||移动时距离
public float minZoomDistance = 2f; //最小缩放距离
public float maxZoomDistance = 3f; //最大缩放距离
public float zoomSpeed = 5f; //缩放速度
[Header("---------------移动---------------")]
public float moveSpeed = 0.3f; //移动速度
[Header("---------------旋转---------------")]
public float rotateSpeed = 1f; //旋转速度
public float minCamHeight = 0.1f; //最小相机高度
public float maxCamHeight = 25f; //最大相机高度
public float currentCamHeight; //当前相机高度
[Header("---------------private---------------")]
[SerializeField]
private int segments = 32; //圆的线段数
[SerializeField]
private float angle; //当前角度
[SerializeField]
private float camRadius; //圆半径
[SerializeField]
private Vector3 operatingResetPos; //操作点重置位置
[SerializeField]
private Vector3 cameraResetPos; //相机重置位置
[SerializeField]
private bool isResetPosEnd = true; //是否重置结束
private void Start()
{
Init();
}
private void LateUpdate()
{
//实时更新用到的参数,同步操作
UpdateParameter();
if (isResetPosEnd)
{
UpdateZoom();
UpdateMove();
UpdateRotate();
}
LookAtOperatingTrn();
DebugDrawLine();
}
private void OnDrawGizmos()
{
if (!isDrawGizmos) return;
DebugDrawCircle(segments, operatingTrn.position, camRadius, currentCamHeight);
DebugDrawCircle(segments, operatingTrn.position, ZYM_Radius, operatingTrn.position.y);
}
private void Init()
{
ModelInit();
//初始距离
currentZoomDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position);
//初始半径
camRadius = Vector2.Distance(new Vector2(operatingTrn.position.x, operatingTrn.position.z), new Vector2(cameraTrn.position.x, cameraTrn.position.z));
//初始高度
currentCamHeight = cameraTrn.position.y;
//重置角度
AngleRefersh();
//获取相机和操作点重置位置
operatingResetPos = operatingTrn.position;
cameraResetPos = cameraTrn.position;
}
private void ModelInit()
{
switch (camModel)
{
case CamModel.WorldRoaming:
//世界漫游
minZoomDistance = SJ_Zoom_Min;
maxZoomDistance = SJ_Zoom_Max;
break;
case CamModel.WorkingSurface:
//作业面
operatingTrn.position = Vector3.zero;
minZoomDistance = ZYM_Zoom_Min;
maxZoomDistance = ZYM_Zoom_Max;
break;
default:
break;
}
}
private void AngleRefersh()
{
// 计算当前相机位置在物体的水平面上的投影点
Vector3 projectPos = new Vector3(cameraTrn.position.x, operatingTrn.position.y, cameraTrn.position.z);
Vector3 v1 = new Vector3(cameraTrn.position.x, 0, cameraTrn.position.z) - new Vector3(operatingTrn.position.x, 0, operatingTrn.position.z);
// 计算当前相机位置相对于物体中心的水平旋转角度
float horizontalAngle = Vector3.Angle(Vector3.right, projectPos - operatingTrn.position);
if (cameraTrn.position.z <= 0)
{
angle = 360 - horizontalAngle;
}
else
{
angle = horizontalAngle;
}
}
public void ChangeCamModel(CamModel _camModel)
{
camModel = _camModel;
Debug.Log("当前相机模式:" + camModel);
ModelInit();
UpdateParameter();
Rotate();
Zoom();
}
private void UpdateParameter()
{
camRadius = Vector2.Distance(new Vector2(operatingTrn.position.x, operatingTrn.position.z), new Vector2(cameraTrn.position.x, cameraTrn.position.z));
currentCamHeight = Mathf.Clamp(cameraTrn.position.y, minCamHeight, maxCamHeight);
currentZoomDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position);
}
private void UpdateZoom()
{
if (Input.mouseScrollDelta.y != 0)
{
Zoom();
}
}
private void UpdateMove()
{
if (camModel == CamModel.WorkingSurface) return;
if (Input.GetMouseButton(0))
{
Move();
}
}
private void UpdateRotate()
{
if (Input.GetMouseButton(1))
{
Rotate();
//防止在旋转视角时候,使得相机缩放超出最大最小距离
Zoom();
}
}
private void Zoom()
{
//鼠标滑轮值
float scrollWheelValue = Input.GetAxis(MOUSESCROLLWHEEL);
//更新当前距离
currentZoomDistance = currentZoomDistance - (scrollWheelValue * zoomSpeed);
// 计算A点到B点的向量
Vector3 vectorAB = cameraTrn.position - operatingTrn.position;
// 将向量AB归一化
Vector3 normalizedVectorAB = vectorAB.normalized;
//限制距离
currentZoomDistance = Mathf.Clamp(currentZoomDistance, minZoomDistance, maxZoomDistance);
// 计算新的A点到B点的距离
float newDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position) - currentZoomDistance;
// 计算新的A点的位置
Vector3 newpointA = cameraTrn.position - normalizedVectorAB * newDistance;
//限制高度
currentCamHeight = Mathf.Clamp(newpointA.y, minCamHeight, maxCamHeight);
//更新位置
cameraTrn.transform.position = new Vector3(newpointA.x, currentCamHeight, newpointA.z);
}
private void Move()
{
float deltaX = Input.GetAxis(MOUSEX) * moveSpeed;
float deltaY = Input.GetAxis(MOUSEY) * moveSpeed;
Vector3 newPosX = -deltaX * cameraTrn.right;
Vector3 newPosY = -deltaY * cameraTrn.forward;
operatingTrn.position += new Vector3(newPosX.x, 0, newPosX.z);
operatingTrn.position += new Vector3(newPosY.x, 0, newPosY.z);
}
private void Rotate()
{
float deltaX = Input.GetAxis(MOUSEX) * rotateSpeed;
float deltaY = Input.GetAxis(MOUSEY) * rotateSpeed;
currentCamHeight = Mathf.Clamp(cameraTrn.position.y - deltaY, minCamHeight, maxCamHeight);
angle -= deltaX;
while (angle > 360.0f)
{
angle -= 360.0f;
}
float x = operatingTrn.position.x + camRadius * Mathf.Cos(angle * Mathf.Deg2Rad);
float z = operatingTrn.position.z + camRadius * Mathf.Sin(angle * Mathf.Deg2Rad);
float y = currentCamHeight;
cameraTrn.position = new Vector3(x, y, z);
}
private void LookAtOperatingTrn()
{
switch (camModel)
{
case CamModel.WorldRoaming:
cameraTrn.LookAt(operatingTrn);
break;
case CamModel.WorkingSurface:
Vector3 targetPos = GetWorkingSurfaceLookArPos();
cameraTrn.LookAt(targetPos);
break;
default:
break;
}
}
public void CameraResetPos()
{
isResetPosEnd = false;
operatingTrn.DOMove(operatingResetPos, 1f);
cameraTrn.DOMove(cameraResetPos, 1f).onComplete += () =>
{
isResetPosEnd = true;
AngleRefersh();
};
}
private Vector3 GetWorkingSurfaceLookArPos()
{
float distance = 60;
Vector2 center = new Vector2(operatingTrn.position.x, operatingTrn.position.z);
Vector2 pointA = new Vector2(cameraTrn.position.x, cameraTrn.position.z);
Vector3 pointB_V3 = (new Vector3(operatingTrn.position.x, 0, operatingTrn.position.z) - new Vector3(cameraTrn.position.x, 0, cameraTrn.position.z)).normalized * distance;
Vector2 pointB = new Vector2(pointB_V3.x, pointB_V3.z);
Vector3 intersectionPos = GetIntersectionPos(pointA, pointB, center, ZYM_Radius);
if (isDrawGizmos)
{
Debug.DrawLine(new Vector3(pointA.x, 0, pointA.y), pointB_V3, Color.red);
Debug.DrawLine(cameraTrn.position, intersectionPos, Color.blue);
Debug.DrawLine(cameraTrn.position, new Vector3(pointA.x, 0, pointA.y), Color.red);
}
return intersectionPos;
}
private Vector3 GetIntersectionPos(Vector2 pointA, Vector2 pointB, Vector2 center, float radius)
{
Vector2 direction = pointB - pointA;
float a = Vector2.Dot(direction, direction);
float b = 2 * Vector2.Dot(direction, pointA - center);
float c = Vector2.Dot(pointA - center, pointA - center) - radius * radius;
float discriminant = b * b - 4 * a * c;
Vector2 intersection1;
Vector2 intersection2;
if (discriminant >= 0)
{
float t1 = (-b + Mathf.Sqrt(discriminant)) / (2 * a);
float t2 = (-b - Mathf.Sqrt(discriminant)) / (2 * a);
intersection1 = pointA + t1 * direction;
intersection2 = pointA + t2 * direction;
//Debug.Log("Intersection 1: " + intersection1);
//Debug.Log("Intersection 2: " + intersection2);
return new Vector3(intersection1.x, 0, intersection1.y);
}
else
{
Debug.Log("没有交点");
}
return Vector3.zero;
}
void OnGUI()
{
if (GUI.Button(new Rect(10, 600, 200, 60), "切换相机模式"))
{
ChangeCamModel(camModel == CamModel.WorkingSurface ? CamModel.WorldRoaming : CamModel.WorkingSurface);
}
//if (GUI.Button(new Rect(10, 100, 200, 60), "重置位置"))
//{
// CameraResetPos();
//}
}
private void DebugDrawLine()
{
Debug.DrawLine(operatingTrn.position, cameraTrn.position, Color.green);
//Debug.DrawLine(Vector3.zero, Vector3.right * 30, Color.blue);
}
public void DebugDrawCircle(int _segments, Vector3 _center, float _radius, float _height = 0)
{
_center = new Vector3(_center.x, _height, _center.z);
Gizmos.color = Color.yellow;
float anglePerSegment = 360.0f / _segments;
Vector3 start = _center + _radius * Vector3.right;
Vector3 end = start;
for (int i = 0; i < _segments; i++)
{
end = _center + Quaternion.Euler(0.0f, anglePerSegment, 0.0f) * (end - _center).normalized * _radius;
Gizmos.DrawLine(start, end);
start = end;
}
Gizmos.DrawLine(end, _center + _radius * Vector3.right);
}
}
public enum CamModel
{
/// <summary> 世界漫游 </summary>
WorldRoaming,
/// <summary> 作业面 </summary>
WorkingSurface,
}