ZhangZhouSpecialEquipment/Assets/Scripts/SBFJ/SmoothUi3DCamera.cs

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;
}
}