zawazawa雑記

【Unity】ボタンの下にあるオブジェクトへのタップイベントを無効化する

想定

UnityでiPhoneのARkitを使った簡単なアプリを作っている時にぶつかった課題です。

ボタンの下は押したくない

uGUIを設置した時に、ボタンの下に検出された平面のタッチイベントまで取得してしまって、意図しない挙動をしてしまった。

なんだか色々解決策がある...

でも絶対もっと簡単にやれるって!って思って調べたところ本当に簡単にできました。

あくまで、自分のケースですが。

手法

UnityARHitTestExample.csスクリプトのUpdate関数内の条件分岐に一言「ボタンがあればタッチイベントを無視しますよ」と加えるだけ。

あ、あとスクリプトの頭にusing UnityEngine; using UnityEngine.EventSystems;の2行を加えるだけ。

        // Update is called once per frame
        void Update () {
           #if UNITY_EDITOR   //we will only use this script on the editor side, though there is nothing that would prevent it from working on device
            if (Input.GetMouseButtonDown (0)) {
                Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
                RaycastHit hit;
                
                //we'll try to hit one of the plane collider gameobjects that were generated by the plugin
                //effectively similar to calling HitTest with ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent
                if (Physics.Raycast (ray, out hit, maxRayDistance, collisionLayer)) {
                    //we're going to get the position from the contact point
                    m_HitTransform.position = hit.point;
                    Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));

                    //and the rotation from the transform of the plane collider
                    m_HitTransform.rotation = hit.transform.rotation;
                }
            }
           #else
            if (Input.touchCount > 0 && m_HitTransform != null)
            {
                var touch = Input.GetTouch(0);

###################### ここのした一行に手を加えるだけ!!! ###################### 
                if ((touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved) && !EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) 
############################################################################
                {
                    var screenPosition = Camera.main.ScreenToViewportPoint(touch.position);
                    ARPoint point = new ARPoint {
                        x = screenPosition.x,
                        y = screenPosition.y
                    };

                    // prioritize reults types
                    ARHitTestResultType[] resultTypes = {
                        ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent, 
                        // if you want to use infinite planes use this:
                        //ARHitTestResultType.ARHitTestResultTypeExistingPlane,
                        ARHitTestResultType.ARHitTestResultTypeHorizontalPlane, 
                        ARHitTestResultType.ARHitTestResultTypeFeaturePoint
                    }; 
                    
                    foreach (ARHitTestResultType resultType in resultTypes)
                    {
                        if (HitTestWithResultType (point, resultType))
                        {
                            return;
                        }
                    }
                }
            }
           #endif

        }

本当に簡単にできた。優勝。

ポイントはEventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)っぽいですね。

参考にさせていただいたサイト

nn-hokuson.hatenablog.com