Unity ボリューム スライダーが円弧に沿って移動する

1.音量スライダーの動き

1. スライダがスライドするとき、その運動軌跡は大円の円弧エッジに沿って延長されます.
2. スライダは無限にスライドすることはできませんが、両端にストッパーがあり、ストッパーの位置に移動すると、下に移動できなくなります. 、しかし、元に戻すことができます
3.マウスをスライダーの上に置くと、音量値と操作プロンプトが表示されます
4.スライダーを移動すると、常に音量値が表示されます.移動を停止すると、音量値が消えます
写真の説明を追加してください

2.UIの実装

下の図に示すように:
1. スライダーの動きは大円の中心を中心に回転することで実現されるため、スライドすると大円が回転し、スライダーは大円のサブオブジェクトになります. 2 .
スライダーの移動は、マウスを左右に動かすことで実現されます
3. ボリューム値は、夾角を計算することで得られます
ここに画像の説明を挿入

3. アイデア

1. 現在のスライダーの位置が表すボリューム値は? 例 [50%]

スライダ A の可動角度範囲の計算: 角度 BOC
スライダ A の現在位置の角度計算: 角度 BOA
ボリューム = 角度 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. マウスでスライダーを左右にドラッグすると、スライダーが大円に沿って回転します

マウス×成分の取得

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

リミットの実現
左上限:スライダ Ax <= Cx のとき、左に回せなくなります
右下リミット:スライダ Ay <= By のとき、下に回せなくなります
ここに画像の説明を挿入

//极限位控制
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;
}

4.コード

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

おすすめ

転載: blog.csdn.net/dzj2021/article/details/130362734