using UnityEngine; /// /// 此代码挂载到相机上, /// 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() { } /// /// 设置相机的初始状态 /// /// /// /// 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; } }