You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何实现可拖拽并带惯性旋转的转盘UI?

实现带惯性旋转的可拖拽UI元素

要实现拖拽松开后的惯性旋转,并能控制旋转时长和速度,你需要补充以下改动:

  1. 实现IPointerUpHandler接口来响应鼠标/触摸松开事件
  2. 记录拖拽过程中的角速度,以此作为惯性旋转的初始速度
  3. 通过协程实现减速旋转的逻辑,同时暴露可调整参数来控制旋转行为

以下是完整的修改代码:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:22:16