您现在的位置是:首页 >技术交流 >Unity音量滑块沿弧形移动网站首页技术交流

Unity音量滑块沿弧形移动

dzj2021 2023-06-14 00:00:02
简介Unity音量滑块沿弧形移动

一、音量滑块的移动

1、滑块在滑动的时候,其运动轨迹沿着大圆的弧边展开
2、滑块不能无限滑动,而是两端各有一个挡块,移动到挡块位置,则不能往下移动,但可以折回
3、鼠标悬停滑块时,给出音量值和操作提示
4、移动滑块的时候,始终提示音量的值,停止移动后,音量值消失
请添加图片描述

二、UI实现

如下图所示:
1、滑块的移动是围绕大圆的圆心旋转实现的,所以滑动的时候,是大圆在旋转,滑块是大圆的子物体
2、滑块移动是通过鼠标左右移动来实现的
3、音量值是通过夹角计算来获取的
在这里插入图片描述

三、思路

1、当前滑块位置代表多大的音量值 e.g.[50%]

滑块A可移动的角度范围计算:角度BOC
滑块A当前位置的角度计算:角度BOA
volume = 角度BOA / 角度BOC

如何计算角度?


    /// <summary>
    /// 计算两条射线之间的夹角(AB,AC -> ∠BAC)
    /// </summary>
    /// <param name="A">原点</param>
    /// <param name="B">位置1</param>
    /// <param name="C">位置2</param>
    /// <returns>夹角(以度为单位)</returns>
    public static float GetClamAngle(Vector3 A, Vector3 B, Vector3 C)
    {
        // 计算向量 AB
        Vector3 AB = B - A;
        // 计算向量 AC
        Vector3 AC = C - A;
        // 计算 AB 和 AC 之间的夹角(以度为单位)
        float angle = Vector3.Angle(AB, AC);
        // 返回夹角
        return angle;
    }

计算可以滑动的角度范围值

//计算滑块运行区间的总的角度范围
allAngle = GetClamAngle(O.transform.position, B.transform.position,
            C.transform.position);

在这里插入图片描述

2、鼠标左右拖拽滑块的时候,滑块沿着大圆进行旋转

鼠标x分量的获取

PointerEventData .delta.x

拖拽旋转的实现

//拖拽中:
ObjectHandle.GetComponent<EventTrigger>().AddListener(EventTriggerType.Drag, (PointerEventData eventData) =>
{
    float direction = Mathf.Sign(eventData.delta.x);

    Quaternion rotation = Quaternion.AngleAxis(direction * rotateSpeed, Vector3.forward);
    ObjectToRotate.transform.rotation *= rotation;
});

限位的实现
左上限位:滑块A.x <= C.x的时候,不能再往左转
右下限位:滑块A.y <= B.y的时候,不能再往下转
在这里插入图片描述

//极限位控制
if (ObjectHandle.transform.position.x <= leftBlock.transform.position.x)
{
    ObjectHandle.transform.position = leftBlock.transform.position;
}
if (ObjectHandle.transform.position.y <= rightBlock.transform.position.y)
{
    ObjectHandle.transform.position = rightBlock.transform.position;
}

四、代码

using System;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using static txlib;

/// <summary>
/// 音量控制:拖动bar进行进行滑动,左上位置为最高音量,右下位置为最低音量
/// </summary>
public class DragVolumBar : MonoBehaviour
{
    /// <summary>
    /// 要旋转的物体
    /// </summary>
    [Header("要旋转的物体")]
    [SerializeField]
    public GameObject ObjectToRotate;

    /// <summary>
    /// 控制旋转的bar
    /// </summary>
    [Header("控制旋转的bar")]
    [SerializeField]
    public GameObject ObjectHandle;

    /// <summary>
    /// 左侧挡板
    /// </summary>
    [Header("左侧挡板")]
    [SerializeField]
    public GameObject leftBlock;

    /// <summary>
    /// 右侧挡板
    /// </summary>
    [Header("右侧挡板")]
    [SerializeField]
    public GameObject rightBlock;

    /// <summary>
    /// 旋转的速度包含方向
    /// </summary>
    [Header("旋转的速度包含方向")]
    [SerializeField] public float rotateSpeed = 10f;

    /// <summary>
    /// 用于显示音量值的text
    /// </summary>
    [Header("用于显示音量值的text")]
    [SerializeField]
    public TMP_Text textVolume;

    /// <summary>
    /// 音量大小
    /// </summary>
    public static float volume;

    /// <summary>
    /// 滑块滑动时的角度区间范围
    /// </summary>
    private float allAngle;

    /// <summary>
    /// 计算两条射线之间的夹角(AB,AC -> ∠BAC)
    /// </summary>
    /// <param name="A">原点</param>
    /// <param name="B">位置1</param>
    /// <param name="C">位置2</param>
    /// <returns>夹角(以度为单位)</returns>
    public static float GetClamAngle(Vector3 A, Vector3 B, Vector3 C)
    {
        // 计算向量 AB
        Vector3 AB = B - A;
        // 计算向量 AC
        Vector3 AC = C - A;
        // 计算 AB 和 AC 之间的夹角(以度为单位)
        float angle = Vector3.Angle(AB, AC);
        // 返回夹角
        return angle;
    }

    // Start is called before the first frame update
    void Start()
    {
        textVolume.gameObject.SetActive(false);

        //计算滑块运行区间的总的角度范围
        allAngle = GetClamAngle(ObjectToRotate.transform.position, leftBlock.transform.position,
            rightBlock.transform.position);

        if (!ObjectHandle.GetComponent<EventTrigger>()) ObjectHandle.AddComponent<EventTrigger>();

        #region 音量滑块拖动
        //开始拖拽:
        ObjectHandle.GetComponent<EventTrigger>().AddListener(EventTriggerType.BeginDrag, async (PointerEventData eventData) =>
        {
            textVolume.gameObject.SetActive(true);
        });

        //拖拽中:
        ObjectHandle.GetComponent<EventTrigger>().AddListener(EventTriggerType.Drag, (PointerEventData eventData) =>
        {
            float direction = Mathf.Sign(eventData.delta.x);

            Quaternion rotation = Quaternion.AngleAxis(direction * rotateSpeed, Vector3.forward);
            ObjectToRotate.transform.rotation *= rotation;

            //极限位控制
            if (ObjectHandle.transform.position.x <= leftBlock.transform.position.x)
            {
                ObjectHandle.transform.position = leftBlock.transform.position;
            }
            if (ObjectHandle.transform.position.y <= rightBlock.transform.position.y)
            {
                ObjectHandle.transform.position = rightBlock.transform.position;
            }

            var angle = GetClamAngle(ObjectToRotate.transform.position, ObjectHandle.transform.position,rightBlock.transform.position);
            volume = angle / allAngle;
            Debug.Log($"总角度:{allAngle},当前角度:{angle} ,声音值:{(int)(100 * volume)}");
            textVolume.text = $"{(int)(100 * volume)}%";
        });

        //结束拖拽:延缓隐藏音量值
        ObjectHandle.GetComponent<EventTrigger>().AddListener(EventTriggerType.EndDrag, async (PointerEventData eventData) =>
        {
            await UniTask.Delay(TimeSpan.FromSeconds(0.2f),cancellationToken:this.GetCancellationTokenOnDestroy());
            textVolume.gameObject.SetActive(false);
        });
        #endregion

        #region 音量滑块鼠标悬停时,显示音量
        ObjectHandle.GetComponent<EventTrigger>().AddListener(EventTriggerType.PointerEnter, async (PointerEventData eventData) =>
        {
            textVolume.gameObject.SetActive(true);
            var angle = GetClamAngle(ObjectToRotate.transform.position, ObjectHandle.transform.position, rightBlock.transform.position);
            volume = angle / allAngle;
            textVolume.text = $"{(int)(100 * volume)}% <color=blue>鼠标左右拖拽滑块来调节音量</color>";
        });
        #endregion
    }
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。