NinaLabo

個人ゲーム開発者の技術メモ

【Unity】uGUIのオブジェクトをタッチしているか判定する

実装方法

EventSystem.current.IsPointerOverGameObject ()

で判定できます。ただし、これだと実機ではうまくいきません。

EventSystem.current.IsPointerOverGameObject (fingerId)

実機の場合は、fingerIdも指定しないといけません。fingerId は Input#GetTouch で取得できる Touch オブジェクトのプロパティから取得できます。

マウス入力も端末でのタッチ入力も両方対応する場合は、引数なしと引数ありのメソッド両方を呼び出さないといけないようです。

いつ使用するのか

開発中のローグライクゲームの場合、基本的なキャラの操作は Input クラス の値を見て判断しています。マウスからの入力なら Input.GetMouseButtonDown (0) 、実機でのタッチ入力なら Input.GetTouch (0) を利用して入力した位置を取得して処理しています。ただ、手前のレイヤーにある ボタンなどのUIは uGUI で実装しており、ボタンを押したなどの入力は uGUIのイベントシステムに任せています。

ユーザーからの入力を処理しているところが2ヶ所あるので、何も考えずに実装すると、レイヤーが重なっている箇所は、ボタンもキャラも両方反応してしまいます。

f:id:ninagreen:20160623230338p:plain

これを防ぐには、uGUIに対して入力した場合は、それ以外の入力処理を実行しないようにする必要があります。今回はマルチタッチは対応しないので、fingerIdを1つだけ受け取る、こんな感じのメソッドを用意することで対応しました。

 private bool _IsPointerOverUGUIObject (int fingerId)
{
    EventSystem eventSystem = EventSystem.current;
    if (eventSystem != null)
    {
        // マウスでの判定
        if (eventSystem.IsPointerOverGameObject ()) {
            return true;
        }

        // タッチでの判定
        if (eventSystem.IsPointerOverGameObject (fingerId)) {
            return true;
        }
    }
    return false;
}

追記: 実機でうまく動きません

UnityEditor上では上記の実装(IsPointOverGameObjectを使用する方法)でうまくいくのですが、実機(iPhone6s/iOS9.2)だと挙動が不安定でうまく動いてくれませんでした。試行錯誤したものの、結局よくわからず、手動でRayを飛ばして確認する方式に変更しました。

PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = screenPosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;

下記のスレッドを参考にさせてもらいました。

 https://forum.unity3d.com/threads/ispointerovereventsystemobject-always-returns-false-on-mobile.265372/

 

参考記事

[Unity]uGUIが被ってる場合はオブジェクトタップの処理を止めたい|杏z 学習帳

GameObjectが重なっている時uGUIで配置したボタンだけタッチに反応させる [stepism@Unityメモ]