サイトアイコン RのWeb制作

[Unity]かんたんに編集・管理ができるボタン向けカスタムクラスのコード紹介

「ボタンが増えて、変更したり管理がめんどくさい・・・!」そんなあなたに。
Unity向け、編集が容易なボタンのカスタムクラスのコードを紹介します。

特徴

・クリック・長押し・スワイプ判定対応のクラスです。
・CustomButtonUI.csを変更することで、同じスクリプトをアタッチしているオブジェクトのクリック時の挙動やクリック音などを一括で管理・変更可能です。
・複数クラスを作ることで、「別の挙動で統一したい!」「別の音で統一したい!」ということもできます。

使い方

①対象のオブジェクトの親にからオブジェクトを作成し、そこにアタッチして利用してください。

例:Imageオブジェクトをクリック判定させたい場合
(1)ImageGoldオブジェクト(空オブジェクトを)作り、そこにスクリプトをアタッチします。
(2)Canvas RendererとCanvas Groupを追加でアタッチします。
(3)アタッチしたスクリプトのCanvas Group変数に、自身のCanvas Groupを選択(またはドロップダウンで指定)します。

※コピペすると、そのオブジェクトも全く同じ挙動をします。
※CustomButtonUI.csを変更すると、元のオブジェクトもコピペしたオブジェクトも変更後の挙動をします。

②クリックイベントを実装してください。
アタッチしたオブジェクトに対し、クリックイベントを入れてください。

// 定義
[SerializeField] GameObject objBtnPractice;

// どこぞに入れて...
objBtnPractice.GetComponent<CustomButtonUI>().onClickCallback = () => {
    // ここに実行したい関数を入れる
};

コード本体

using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;

// スワイプの方向を示すenum
public enum SwipeDirection
{
    None,
    Up,
    Down,
    Left,
    Right
}

// ボタン用クラス
public class CustomButtonUI : MonoBehaviour,
    IPointerClickHandler,
    IPointerDownHandler,
    IPointerUpHandler
{
    //------------------------------------------------------//
    // 設定
    //------------------------------------------------------//
    // 一般
    [SerializeField] private CanvasGroup buttonCanvasGroup;

    // クリック判定
    public System.Action onClickCallback;

    // 長押し判定
    public System.Action onPressLongCallback;
    [SerializeField] private float longPressDuration = 0.5f;
    private float longPressStartTime = 0f;
    private bool isPointerDown = false;

    // スワイプ判定
    public System.Action<SwipeDirection> onSwipeCallback;
    private Vector2 swipeStartPosition;
    private Vector2 swipeCurrentPosition;
    [SerializeField] private bool detectSwipeOnlyAfterRelease = false;
    [SerializeField] private float swipeThreshold = 20f;

    //------------------------------------------------------//
    // 関数:一般
    //------------------------------------------------------//
    private void Update()
    {
        // 長押し
        if(isPointerDown == true)
        {
            if(Time.time - longPressStartTime > longPressDuration)
            {
                OnPressLong();
                ResetPressLong();
            }
        }

        // スワイプ
        if (Input.touchCount > 0) // タッチ入力(モバイル)
        {
            foreach (Touch touch in Input.touches)
            {
                if (touch.phase == TouchPhase.Began)
                {
                    swipeCurrentPosition = touch.position;
                    swipeStartPosition = touch.position;
                }

                if (touch.phase == TouchPhase.Moved)
                {
                    if (!detectSwipeOnlyAfterRelease)
                    {
                        swipeCurrentPosition = touch.position;
                        CheckSwipe();
                    }
                }

                if (touch.phase == TouchPhase.Ended)
                {
                    swipeCurrentPosition = touch.position;
                    CheckSwipe();
                }
            }
        }
        // マウス入力(Unity Editor用)
        else
        {
            if (Input.GetMouseButtonDown(0))
            {
                swipeCurrentPosition = Input.mousePosition;
                swipeStartPosition = Input.mousePosition;
            }

            if (Input.GetMouseButton(0))
            {
                if (!detectSwipeOnlyAfterRelease)
                {
                    swipeCurrentPosition = Input.mousePosition;
                    CheckSwipe();
                }
            }

            if (Input.GetMouseButtonUp(0))
            {
                swipeCurrentPosition = Input.mousePosition;
                CheckSwipe();
            }
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        transform.DOScale(0.95f, 0.24f).SetEase(Ease.OutCubic);
        buttonCanvasGroup.DOFade(0.8f, 0.24f).SetEase(Ease.OutCubic);

        // カウント開始
        isPointerDown = true;
        longPressStartTime = Time.time;

        // スワイプ開始位置記録
        swipeStartPosition = eventData.position;
        swipeCurrentPosition = eventData.position;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        transform.DOScale(1f, 0.24f).SetEase(Ease.OutCubic);
        buttonCanvasGroup.DOFade(1f, 0.24f).SetEase(Ease.OutCubic);

        // スワイプ終了位置記録
        swipeCurrentPosition = eventData.position;
        CheckSwipe();

        // リセット
        ResetPressLong();
    }

    //------------------------------------------------------//
    // 関数:クリック
    //------------------------------------------------------//
    public void OnPointerClick(PointerEventData eventData)
    {
        if(onClickCallback != null)
        {
            // サウンド
            // SoundManager.instance.PlaySE(SoundDataSE.Type.ClickUI);

            // invoke
            onClickCallback.Invoke();
        }
        Logging.Log($"[{name}] クリック");
    }

    //------------------------------------------------------//
    // 関数:長押し
    //------------------------------------------------------//
    public void OnPressLong()
    {
        if(onPressLongCallback != null)
        {
            // サウンド
            // SoundManager.instance.PlaySE(SoundDataSE.Type.ClickLong);

            // invoke
            onPressLongCallback.Invoke();
        }
        Logging.Log($"[{name}] 長押し");
    }

    // 状態をリセット
    private void ResetPressLong()
    {
        isPointerDown = false;
        longPressStartTime = 0f;
    }

    //------------------------------------------------------//
    // 関数:スワイプ
    //------------------------------------------------------//
    // スワイプ判定
    private void CheckSwipe()
    {
        SwipeDirection direction = SwipeDirection.None;

        // しきい値以上縦方向にスワイプしたかどうか判定する
        if (GetVerticalDistance() > swipeThreshold && GetVerticalDistance() > GetHorizontalDistance())
        {
            if (swipeCurrentPosition.y - swipeStartPosition.y > 0)
            {
                direction = SwipeDirection.Up;
            }
            else if (swipeCurrentPosition.y - swipeStartPosition.y < 0)
            {
                direction = SwipeDirection.Down;
            }
            swipeStartPosition = swipeCurrentPosition;
        }
        // しきい値以上横方向にスワイプしたかどうか判定する
        else if (GetHorizontalDistance() > swipeThreshold && GetHorizontalDistance() > GetVerticalDistance())
        {
            if (swipeCurrentPosition.x - swipeStartPosition.x > 0)
            {
                direction = SwipeDirection.Right;
            }
            else if (swipeCurrentPosition.x - swipeStartPosition.x < 0)
            {
                direction = SwipeDirection.Left;
            }
            swipeStartPosition = swipeCurrentPosition;
        }

        // スワイプ検出時にコールバック実行
        if (direction != SwipeDirection.None)
        {
            OnSwipe(direction);
        }
    }

    private float GetVerticalDistance()
    {
        return Mathf.Abs(swipeCurrentPosition.y - swipeStartPosition.y);
    }

    private float GetHorizontalDistance()
    {
        return Mathf.Abs(swipeCurrentPosition.x - swipeStartPosition.x);
    }

    private void OnSwipe(SwipeDirection direction)
    {
        if(onSwipeCallback != null)
        {
            // サウンド
            // SoundManager.instance.PlaySE(SoundDataSE.Type.Swipe);

            // invoke
            onSwipeCallback.Invoke(direction);
        }
        Logging.Log($"[{name}] スワイプ: {direction}");
    }

    //------------------------------------------------------//
}

注意点

使わないものがあればコメントアウトしてください
・ボタンの動きを加えるアセットのDOTweenを使っています
・Loggingという拡張クラス(Debugのラッパー)を使ってます

モバイルバージョンを終了