ヽ|∵|ゝ(Fantom) の 開発blog? ホーム » Unity »【Unity】【C#】スワイプ(フリック)を判定、方向を取得してコールバックする

【Unity】【C#】スワイプ(フリック)を判定、方向を取得してコールバックする  


 今回は Unity 上でスワイプ動作を取得してみよう。これと前回の 「一番近い45・90度ごとの角度を求める」 を組み合わせてスマホアプリなどに利用すると、画面をスワイプしてカメラをスイッと回転、なんてことが簡単にできる。


(※) Unity 5.6.1p3 / Windows10(x64) で確認

●スワイプを判定して、方向を取得してコールバックする
using System;
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// スワイプ方向を取得してコールバックする
/// 2017/7/5 Fantom (Unity 5.6.1p3)
/// http://fantom1x.blog130.fc2.com/blog-entry-250.html
///(使い方)
///・適当な GameObject にアタッチして、インスペクタから OnSwipe(Vector2 を1つ引数にとる)にコールバックする関数を登録すれば使用可。
///・またはプロパティ SwipeInput.Direction をフレーム毎監視しても良い(こちらの場合は無し(Vector2.zero)も含まれる)。
///(仕様説明)
///・タッチの移動量(エディタやスマホ以外の場合はマウス)で判定する。画面幅の Valid Width(%)以上移動したときスワイプとして認識する。
///・ただし、移動が制限時間(Timeout)を超えた時は無視する。
///・複数の指では認識できない(※2つ以上の指の場合はピンチの可能性もあるため無効とする)。
///・タッチデバイスを UNITY_ANDROID, UNITY_IOS としているので、他のデバイスも加えたい場合は #if の条件文にデバイスを追加する(Input.touchCount が取得できるもののみ)。
/// </summary>
public class SwipeInput : MonoBehaviour
{
//設定値
public bool widthReference = true; //画面幅(Screen.width)サイズを比率の基準にする(false=高さ(Screen.height)を基準)
public float validWidth = 0.25f; //スワイプとして認識する移動量の画面比[画面幅に対する比率](0.0~1.0:1.0で端から端まで。この値より長い移動量でスワイプとして認識する)
public float timeout = 0.5f; //スワイプとして認識する時間(これより短い時間でスワイプとして認識する)

//Local Values
Vector2 startPos; //スワイプ開始座標
Vector2 endPos; //スワイプ終了座標
float limitTime; //スワイプ時間制限(この時刻を超えたらスワイプとして認識しない)
bool pressing; //押下中フラグ(単一指のみの取得にするため)

Vector2 swipeDir = Vector2.zero; //取得したスワイプ方向(フレーム毎判定用)[zeroがなしで、left, right, up, downが方向]

//スワイプ方向取得プロパティ(フレーム毎取得用)
public Vector2 Direction {
get { return swipeDir; }
}

//スワイプイベントコールバック(インスペクタ用)
[Serializable]
public class SwipeHandler : UnityEvent<Vector2> {
}

public SwipeHandler OnSwipe; //引数の Vector2 でスワイプ方向を返す


//アクティブになったら、初期化する(アプリの中断などしたときはリセットする)
void OnEnable()
{
pressing = false;
}

// Update is called once per frame
void Update()
{
swipeDir = Vector2.zero; //フレーム毎にリセット

#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS) //タッチで取得したいプラットフォームのみ
if (Input.touchCount == 1) //複数の指は不可とする(※2つ以上の指の場合はピンチの可能性もあるため)
#endif
{
if (!pressing && Input.GetMouseButtonDown(0)) //押したとき(左クリック/タッチが取得できる)
{
pressing = true;
startPos = Input.mousePosition;
limitTime = Time.time + timeout;
}
else if (pressing && Input.GetMouseButtonUp(0)) //既に押されているときのみ(※この関数は2つ以上タッチの場合、どの指か判別できないので注意)
{
pressing = false;

if (Time.time < limitTime) //時間制限前なら認識
{
endPos = Input.mousePosition;

Vector2 dist = endPos - startPos;
float dx = Mathf.Abs(dist.x);
float dy = Mathf.Abs(dist.y);
float requiredPx = widthReference ? Screen.width * validWidth : Screen.height * validWidth;

if (dy < dx) //横方向として認識
{
if (requiredPx < dx) //長さを超えていたら認識
swipeDir = Mathf.Sign(dist.x) < 0 ? Vector2.left : Vector2.right;
}
else //縦方向として認識
{
if (requiredPx < dy) //長さを超えていたら認識
swipeDir = Mathf.Sign(dist.y) < 0 ? Vector2.down : Vector2.up;
}

//コールバックイベント
if (swipeDir != Vector2.zero)
{
if (OnSwipe != null)
OnSwipe.Invoke(swipeDir); //UnityEvent
}
}
}
}
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS) //タッチで取得したいプラットフォームのみ
else //タッチが1つでないときは無効にする(※2つ以上の指の場合はピンチの可能性もあるため)
{
pressing = false;
}
#endif
}
}

 実の所を言うと、このスワイプ判定はググれば色々出てくるのだが、実際にスマートフォンで使ってみると、上手く行かないケースが多かったので自分なりに改良してみたものだ。例えばスマホでゲームする際には端末を横にして両指(左右の親指)で移動、ジャンプなど操作する場合も多いと思うが、このとき複数の指を認識してしまうため、これをスワイプと誤認識するものが多かった。あと移動量が絶対量の場合、画面サイズの違う端末での認識が異なってしまうことや、制限時間がないためにゆっくり指を動かす動作もスワイプとして誤認識する場合もあったので、それらを正しく認識できるように改良したものと言っても良い。

 また、できればエディタ上での動作確認やマウスでのスワイプ認識もできたら便利と考えたため、Touch 系での取得や判定は極力避け、Input.GetMouseButtonDown() のようなマウス操作の取得(タッチも取得できる)で書いてある。本来ならタッチの指のID(Touch.fingerId)でユニークな指の判定をするべきだと思うが、押下中フラグ(pressing)と Input.touchCount を1つでユニーク動作にしてるため、指の判定は省略してある。なのでPCなどで複数のマウスを使ったりすれば誤認識するかもしれないが、まぁ、普通に使う分には大丈夫だろう。必要あれば指ID(ポインタID)での判別を追加しても良いかも知れない。

 プラットフォームに関しては、タッチデバイスとして Android と iOS しか考えてないので、必要あればプリプロセッサディレクティブ(#if 文)に条件を追加して欲しい。これらは Input.touchCount が取得できるものに限られる。

 あと、コールバックイベントはインスペクタで設定(UnityEvent)するようにしてあるが、コードだけにしたいなら、Action を使ったコールバックや、直接 delegate でコールバックするように書き換えても良いだろう。もちろんそのままで UnityEvent.AddListener を使ってコードから追加する方法もある。以下のページに色々実装方法を載せてあるので、自由に改造して使って欲しい。

【Unity】【C#】UnityEvent, Action, delegate, interface でのコールバック実装方法とインスペクタでの登録


適当なスクリプトに OnSwipe(Vector2) のようなメソッドを書いて、インスペクタで登録する。


スマホ版の「プロ生ちゃん in Action Game!」に実装済み。
画面をスワイプすると、カメラがキャラの廻りをぐるりと90度ごと回転して
眺められるようになっている(※ただし、このゲームには特に必要ない機能(笑))。
>> PronamaChan in Action Game!(Android 版)



(関連記事)
【Unity】【C#】n度ごとの角度を返す(一定角度ごとの切り捨て、切り上げ、四捨五入)
【Unity】【C#】UnityEvent, Action, delegate, interface でのコールバック実装方法とインスペクタでの登録


スポンサーサイト

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  C# 
tb: 0   cm: --


トラックバック

トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/250-b1578c36
この記事にトラックバックする(FC2ブログユーザー)

プロフィール

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop