155 lines
5.4 KiB
C#
155 lines
5.4 KiB
C#
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// 此代码挂载到相机上,
|
|
/// </summary>
|
|
public class SmoothUi3DCamera : MonoBehaviour
|
|
{
|
|
public static SmoothUi3DCamera instance;
|
|
// 用于旋转的变换
|
|
public Transform pivot;
|
|
// 透视变换的偏移量
|
|
public Vector3 pivotOffset = Vector3.zero;
|
|
// 目标变换
|
|
public Transform target;
|
|
// 与目标的距离
|
|
public float distance = 10.0f;
|
|
// 距离的最小值
|
|
public float minDistance = 5f;
|
|
// 距离的最大值
|
|
public float maxDistance = 15f;
|
|
// 缩放速度
|
|
public float zoomSpeed = 1f;
|
|
// 水平旋转速度
|
|
public float xSpeed = 250.0f;
|
|
// 垂直旋转速度
|
|
public float ySpeed = 250.0f;
|
|
// 触摸旋转速度因子
|
|
[Header("触摸旋转速度因子")]
|
|
public float touchSpeed = 0.05f; // 测试显示0.05f 效果更佳
|
|
// 是否允许垂直倾斜
|
|
public bool allowYTilt = true;
|
|
// 垂直倾斜的最小角度限制
|
|
public float yMinLimit = -90f;
|
|
// 垂直倾斜的最大角度限制
|
|
public float yMaxLimit = 90f;
|
|
// 水平旋转角度
|
|
private float x = 0.0f;
|
|
// 垂直旋转角度
|
|
private float y = 0.0f;
|
|
// 目标水平旋转角度
|
|
private float targetX = 0f;
|
|
// 目标垂直旋转角度
|
|
private float targetY = 0f;
|
|
// 目标距离
|
|
public float targetDistance = 0f;
|
|
// 水平旋转速度
|
|
private float xVelocity = 1f;
|
|
// 垂直旋转速度
|
|
private float yVelocity = 1f;
|
|
// 缩放速度
|
|
private float zoomVelocity = 1f;
|
|
|
|
// 定义鼠标控制的屏幕范围(左,右,上,下)
|
|
[Header("鼠标控制屏幕范围")]
|
|
public Vector2 screenRangeLeftRight = new Vector2(0f, 1f); // 0f 到 1f 表示整个屏幕宽度
|
|
public Vector2 screenRangeTopBottom = new Vector2(0f, 1f); // 0f 到 1f 表示整个屏幕高度
|
|
|
|
private void Awake()
|
|
{
|
|
instance = this;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
var angles = transform.eulerAngles;
|
|
// 因为是操作的相机,所以我们实际的操作出来是向反的方向
|
|
targetY = x = angles.x;
|
|
targetX = y = ClampAngle(angles.y, yMinLimit, yMaxLimit);
|
|
targetDistance = distance;
|
|
}
|
|
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!pivot) return;
|
|
|
|
// 获取鼠标位置
|
|
Vector2 mousePosition = Input.mousePosition;
|
|
|
|
// 检查鼠标是否在屏幕范围内
|
|
if (mousePosition.x / Screen.width >= screenRangeLeftRight.x && mousePosition.x / Screen.width <= screenRangeLeftRight.y &&
|
|
mousePosition.y / Screen.height >= screenRangeTopBottom.x && mousePosition.y / Screen.height <= screenRangeTopBottom.y)
|
|
{
|
|
|
|
#region 鼠标控制
|
|
// 鼠标中键控制缩放
|
|
var scroll = Input.GetAxis("Mouse ScrollWheel");
|
|
if (scroll > 0.0f) targetDistance -= zoomSpeed;
|
|
else if (scroll < 0.0f)
|
|
targetDistance += zoomSpeed;
|
|
targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance);
|
|
// 鼠标左右键操作旋转
|
|
if (Input.GetMouseButton(0) || (Input.GetMouseButton(1) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))))
|
|
{
|
|
targetX += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
|
|
if (allowYTilt)
|
|
{
|
|
targetY -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
|
|
targetY = ClampAngle(targetY, yMinLimit, yMaxLimit);
|
|
}
|
|
}
|
|
x = Mathf.SmoothDampAngle(x, targetX, ref xVelocity, 0.3f);
|
|
y = allowYTilt ? Mathf.SmoothDampAngle(y, targetY, ref yVelocity, 0.3f) : targetY;
|
|
Quaternion rotation = Quaternion.Euler(y, x, 0);
|
|
distance = Mathf.SmoothDamp(distance, targetDistance, ref zoomVelocity, 0.5f);
|
|
Vector3 position = rotation * new Vector3(0.0f, 0.0f, -distance) + pivot.position + pivotOffset;
|
|
transform.rotation = rotation;
|
|
transform.position = position;
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private static float ClampAngle(float angle, float min, float max)
|
|
{
|
|
if (angle < -360) angle += 360;
|
|
if (angle > 360) angle -= 360;
|
|
return Mathf.Clamp(angle, min, max);
|
|
}
|
|
|
|
[ContextMenu("Load Initialize View")]
|
|
public void LoadInitializeView()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置相机的初始状态
|
|
/// </summary>
|
|
/// <param name="initialXAngle"></param>
|
|
/// <param name="initialYAngle"></param>
|
|
/// <param name="initialDistance"></param>
|
|
public void InitializeView(float initialXAngle, float initialYAngle, float initialDistance)
|
|
{
|
|
// 设置初始水平旋转角度
|
|
targetX = initialXAngle;
|
|
x = initialXAngle;
|
|
|
|
// 设置初始垂直旋转角度,并考虑角度限制
|
|
targetY = ClampAngle(initialYAngle, yMinLimit, yMaxLimit);
|
|
y = targetY;
|
|
|
|
// 设置初始距离,并考虑距离限制
|
|
targetDistance = Mathf.Clamp(initialDistance, minDistance, maxDistance);
|
|
distance = targetDistance;
|
|
|
|
// 更新相机的位置和旋转
|
|
Quaternion rotation = Quaternion.Euler(y, x, 0);
|
|
Vector3 position = rotation * new Vector3(0.0f, 0.0f, -distance) + pivot.position + pivotOffset;
|
|
transform.rotation = rotation;
|
|
transform.position = position;
|
|
}
|
|
|
|
} |