以下の内容はhttps://hacchi-man.hatenablog.com/entry/2025/03/17/220000より取得しました。


【Unity】範囲選択できるスライダーを作る

はじめに

Unity の標準 Slider コンポーネントは、1 つの値を変更することしかできません。しかし、ゲームや UI で「最小値と最大値を設定したい」といった場面は多くあります。

例えば: - オーディオ設定で、特定の周波数帯を選択 - ゲーム内のフィルター機能(価格の範囲選択など) - キャラクターのパラメータ設定

こうした用途に対応するため、 MinMaxSlider を作成し、最小値と最大値を調整できるスライダーを実装します。

MinMaxSlider の実装

以下のスクリプトでは、Selectable を継承して MinMaxSlider を作成し、2 つのハンドル(最小値用と最大値用)を持つスライダーを実装します。

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityEngine.EventSystems;

[RequireComponent(typeof(RectTransform))]
public class MinMaxSlider : Selectable, IDragHandler
{
    [SerializeField] public RectTransform _handleMinRect;
    [SerializeField] public RectTransform _handleMaxRect;
    [SerializeField] public RectTransform _fillRect;
    
    [SerializeField] private float _minValue = 0f;
    [SerializeField] private float _maxValue = 1f;
    [SerializeField] private float _minLimit = 0f;
    [SerializeField] private float _maxLimit = 1f;
    [SerializeField] private bool _wholeNumbers = false;
    
    private bool _isDraggingMin = false;
    private bool _isDraggingMax = false;
    
    public class SliderValueChangedEvent : UnityEvent<float, float> {}
    
    [SerializeField] private SliderValueChangedEvent _onValueChanged = new SliderValueChangedEvent();
    
    public SliderValueChangedEvent OnValueChanged
    {
        get => _onValueChanged;
        set => _onValueChanged = value;
    }

    protected override void Start()
    {
        base.Start();
        UpdateHandles();
    }

    public override void OnPointerDown(PointerEventData eventData)
    {
        base.OnPointerDown(eventData);
        if (RectTransformUtility.RectangleContainsScreenPoint(_handleMinRect, eventData.position, eventData.pressEventCamera))
        {
            _isDraggingMin = true;
        }
        else if (RectTransformUtility.RectangleContainsScreenPoint(_handleMaxRect, eventData.position, eventData.pressEventCamera))
        {
            _isDraggingMax = true;
        }
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        base.OnPointerUp(eventData);
        _isDraggingMin = false;
        _isDraggingMax = false;
    }

    void IDragHandler.OnDrag(PointerEventData eventData)
    {
        Vector2 localPoint;
        if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
                transform as RectTransform, eventData.position, eventData.pressEventCamera, out localPoint))
            return;
        
        float width = ((RectTransform)transform).rect.width;
        float normalizedValue = Mathf.InverseLerp(-width / 2, width / 2, localPoint.x);
        float value = Mathf.Lerp(_minLimit, _maxLimit, normalizedValue);
            
        if (_wholeNumbers)
        {
            value = Mathf.Round(value);
        }
            
        if (_isDraggingMin)
        {
            if (value > _maxValue)
            {
                (_minValue, _maxValue) = (_maxValue, value);
                _isDraggingMin = false;
                _isDraggingMax = true;
            }
            else
            {
                _minValue = Mathf.Clamp(value, _minLimit, _maxValue - (_wholeNumbers ? 1 : 0.01f));
            }
        }
        else if (_isDraggingMax)
        {
            if (value < _minValue)
            {
                (_maxValue, _minValue) = (_minValue, value);
                _isDraggingMax = false;
                _isDraggingMin = true;
            }
            else
            {
                _maxValue = Mathf.Clamp(value, _minValue + (_wholeNumbers ? 1 : 0.01f), _maxLimit);
            }
        }
        UpdateHandles();
    }
    
    private void UpdateHandles()
    {
        float width = ((RectTransform)transform).rect.width;
        _handleMinRect.anchoredPosition = new Vector2((_minValue - _minLimit) / (_maxLimit - _minLimit) * width, _handleMinRect.anchoredPosition.y);
        _handleMaxRect.anchoredPosition = new Vector2((_maxValue - _minLimit) / (_maxLimit - _minLimit) * width, _handleMaxRect.anchoredPosition.y);
        _fillRect.offsetMin = new Vector2(_handleMinRect.anchoredPosition.x, _fillRect.offsetMin.y);
        _fillRect.offsetMax = new Vector2(_handleMaxRect.anchoredPosition.x - width, _fillRect.offsetMax.y);
        
        OnValueChanged.Invoke(_minValue, _maxValue);
    }
}

まとめ

MinMaxSlider を使用することで、範囲を選択できるスライダーを簡単に作成できます。ゲーム UI や設定画面で便利に使えるので、カスタム UI を作成する際に試してみてください!




以上の内容はhttps://hacchi-man.hatenablog.com/entry/2025/03/17/220000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14