🐈

[Unity] eventを使ってマネージャークラスを汚さずにフリック判定をする

2021/09/07に公開

UnityのInputクラスなどを利用する際、特に個人開発ではGameManagerクラスのUpdate()が煩雑になりがちになってしまいます。
そこで今回はeventを使ってマネージャークラスを汚さずにフリック判定をする実装を行いました。

フリック判定

  • 上/下/右/左 の4方向へのフリック(指のスライド)を取得し、ログ出力を行なっています。
  • 本記事の実装では、UnityEditor, iOS環境にて動作確認済みです。

実装

  • startPosからcurrentPosへの移動距離を参考にフリック判定を行う
    • posDiff以上移動した場合をフリックとする
  • 移動距離がy < xの場合は横フリック、x < yの場合は縦フリックとする。
  • 他UI操作時は無視する
#if UNITY_EDITOR
        if (EventSystem.current.IsPointerOverGameObject())
        {
            return;
        }
#else
        if (Input.touchCount > 0)
        {
            if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
            {
                return;
            }
        }
#endif

ソースコード全文はこちら

GestureController.cs

フリック操作の処理を行います。

GestureController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class GestureController : MonoBehaviour
{
    public delegate void GestureEventHandler();
    public event GestureEventHandler rightFlick;
    public event GestureEventHandler leftFlick;
    public event GestureEventHandler upFlick;
    public event GestureEventHandler downFlick;
    private const float posDiff = 50f;
    private Vector2 startPos = Vector2.zero;
    private Vector2 currentPos = Vector2.zero;
    private bool isPrepared = false;

    void Update()
    {
#if UNITY_EDITOR
        if (EventSystem.current.IsPointerOverGameObject())
        {
            return;
        }
#else
        if (Input.touchCount > 0)
        {
            if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
            {
                return;
            }
        }
#endif

        if (Input.GetMouseButtonDown(0))
        {
            startPos = Input.mousePosition;
            isPrepared = true;
        }

        if (Input.GetMouseButton(0))
        {
            currentPos = Input.mousePosition;
        }

        if (Mathf.Abs(currentPos.x - startPos.x) > Mathf.Abs(currentPos.y - startPos.y))
        {
            if (currentPos.x - startPos.x >= posDiff && isPrepared)
            {
                isPrepared = false;
                RightFlick();
            }
            else if (currentPos.x - startPos.x <= -posDiff && isPrepared)
            {
                isPrepared = false;
                LeftFlick();
            }
        }
        else
        {
            if (currentPos.y - startPos.y >= posDiff && isPrepared)
            {
                isPrepared = false;
                UpFlick();
            }
            else if (currentPos.y - startPos.y <= -posDiff && isPrepared)
            {
                isPrepared = false;
                DownFlick();
            }
        }
    }

    private void RightFlick()
    {
        if (rightFlick != null) { rightFlick(); }
    }

    private void LeftFlick()
    {
        if (leftFlick != null) { leftFlick(); }
    }

    private void UpFlick()
    {
        if (upFlick != null) { upFlick(); }
    }

    private void DownFlick()
    {
        if (downFlick != null) { downFlick(); }
    }
}

TestFlickController.cs

フリック判定のコールバックを登録し、判定時に処理を行います。
こちらのスクリプトを参考に、マネージャークラスに書き換えてください。

TestFlickController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestFlickController : MonoBehaviour
{
    [SerializeField] private GestureController gestureController;

    void Start()
    {
        gestureController.rightFlick += RightFlick;
        gestureController.leftFlick += LeftFlick;
        gestureController.upFlick += UpFlick;
        gestureController.downFlick += DownFlick;
    }

    private void RightFlick()
    {
        Debug.Log("RightFlick");
    }

    private void LeftFlick()
    {
        Debug.Log("LeftFlick");
    }

    private void UpFlick()
    {
        Debug.Log("UpFlick");
    }

    private void DownFlick()
    {
        Debug.Log("DownFlick");
    }
}


実行結果

Sep-07-2021 17-05-45

横フリックだけ利用したい場合など、マネージャークラスのコールバック登録を書き換えるだけで済むので、上記のGestureController.csはそのまま利用することができます。

Discussion