Unityで、タップされた位置がボタンの上だったら反応させない

2016-11-13

Input.touchesでタップの状態を直接見てプレイヤーの操作に反映させるけど、UGUIのボタン上で押されたときには無視したいといったときにどうするか。

UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObjectを使う。

デフォルトだとマウス、タッチのフィンガーIDを渡せばその位置がボタン上かどうか判定できる:

using UnityEngine.EventSystems;

for (int i = 0; i < Input.touchCount; ++i) {
var touch = Input.touches[i];
if (touch.phase == TouchPhase.Began) {
if (!EventSystem.current.IsPointerOverGameObject(touch.fingerId)) {
Debug.Log(touch.fingerId + ": タップ!");
}
}
}

ボタン以外に表示しているUI、例えばTextのなどのRaycast Targetは切っておくこと。


‘2017/06/10: ちゃんと動いてると思ってたんだけど、気づいたらタッチデバイスで動かした時に効いていなかった…おかしいな。

【Unity】uGUIのオブジェクトをタッチしているか判定する - NinaLabo (およびUnity forumの解答)を参考に、

// EventSystem.current.IsPointerOverGameObject(touch.fingerId)
// がうまく動かないので、その代わり
private static List<RaycastResult> raycastResults = new List<RaycastResult>(); // リストを使いまわす
public static bool IsPointerOverUIObject(Vector2 screenPosition) {
// Referencing this code for GraphicRaycaster https://gist.github.com/stramit/ead7ca1f432f3c0f181f
// the ray cast appears to require only eventData.position.
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = screenPosition;

EventSystem.current.RaycastAll(eventDataCurrentPosition, raycastResults);
var over = raycastResults.Count > 0;
raycastResults.Clear();
return over;
}

使用にはtouch.fingerIdの代わりにtouch.positionを渡す。