Unity中如何实现可拖拽并带惯性旋转的转盘UI?
实现带惯性旋转的可拖拽UI元素
要实现拖拽松开后的惯性旋转,并能控制旋转时长和速度,你需要补充以下改动:
- 实现
IPointerUpHandler接口来响应鼠标/触摸松开事件 - 记录拖拽过程中的角速度,以此作为惯性旋转的初始速度
- 通过协程实现减速旋转的逻辑,同时暴露可调整参数来控制旋转行为
以下是完整的修改代码:
using UnityEngine; using UnityEngine.EventSystems; using System.Collections; public class TouchControl : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler { private RectTransform _rectTransform; private Vector2 _initialPosition; private float _angleOffset; private float _lastAngle; private float _currentAngularVelocity; // 可在Inspector面板调整的参数 [Header("惯性旋转设置")] public float friction = 0.95f; // 摩擦系数,越小减速越快 public float minInertiaSpeed = 5f; // 触发惯性的最小角速度 public float maxRotationSpeed = 180f; // 最大旋转速度(限制惯性初始速度) private void Awake() { _rectTransform = GetComponent<RectTransform>(); } public void OnPointerDown(PointerEventData eventData) { _initialPosition = _rectTransform.position; Vector2 mousePosition = eventData.position; Vector2 offset = mousePosition - _initialPosition; _angleOffset = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - _rectTransform.eulerAngles.z; _lastAngle = _rectTransform.eulerAngles.z; _currentAngularVelocity = 0; } public void OnDrag(PointerEventData eventData) { Vector2 mousePosition = eventData.position; Vector2 offset = mousePosition - _initialPosition; float currentAngle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - _angleOffset; // 计算当前角速度(帧间角度差) _currentAngularVelocity = Mathf.DeltaAngle(_lastAngle, currentAngle); // 限制最大转速,避免惯性过猛 _currentAngularVelocity = Mathf.Clamp(_currentAngularVelocity, -maxRotationSpeed, maxRotationSpeed); _rectTransform.eulerAngles = new Vector3(0, 0, currentAngle); _lastAngle = currentAngle; } public void OnPointerUp(PointerEventData eventData) { // 当角速度足够大时,启动惯性旋转协程 if (Mathf.Abs(_currentAngularVelocity) >= minInertiaSpeed) { StopCoroutine(InertiaRotate()); StartCoroutine(InertiaRotate()); } } private IEnumerator InertiaRotate() { float angularSpeed = _currentAngularVelocity; while (Mathf.Abs(angularSpeed) > 0.1f) { // 逐帧减速 angularSpeed *= friction; // 应用旋转,自动处理0-360度循环 _rectTransform.eulerAngles += new Vector3(0, 0, angularSpeed); yield return null; } } }
关键逻辑说明:
- 角速度计算:在
OnDrag中用Mathf.DeltaAngle计算帧间角度差,得到拖拽时的旋转速度,这是惯性的初始动力 - 参数控制:
friction:控制减速快慢,值越接近1,旋转持续时间越长;值越小,停止得越快minInertiaSpeed:只有当拖拽速度超过这个值时,才会触发惯性旋转,避免轻微拖拽也触发maxRotationSpeed:限制最大旋转速度,防止惯性旋转过快
- 惯性旋转协程:松开后通过协程逐帧减少旋转速度,直到速度趋近于0,实现自然的减速停止效果
调整参数实现目标效果:
如果你想让旋转持续更久,就调大friction(比如0.98);想让初始旋转更快,就调大maxRotationSpeed;不想让轻微拖拽触发惯性,就提高minInertiaSpeed。通过组合这些参数,可以模拟类似转盘的旋转效果。
内容的提问来源于stack exchange,提问作者AmateurUnityDeveloper
相关产品推荐
相关产品推荐

