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