web-dev-qa-db-ja.com

Unity3DのIPointerDownHandlerアプローチを使用するが、「画面全体」

Unityでは、シーン内の何かに対する指のタッチ(指の描画)を検出する必要があると言います。

現代のUnityでこれを行う唯一の方法は非常に単純です


ステップ1。そのオブジェクトにコライダーを置きます。 (「地面」またはそれが何であれ何でも。) 1

ステップ2。カメラのインスペクターパネルで、クリックしてPhysicsレイキャスター(関連する2Dまたは3D)を追加します。

ステップ3。以下の例Aのようにコードを使用します。

(ヒント-EventSystemがあることを確認することを忘れないでください... Unityが自動的に追加する場合とそうでない場合があります!)


素晴らしい、これ以上簡単なことはありません。 Unityは、UIレイヤーを通じて最終的にun/propagationを正しく処理します。デスクトップ、デバイス、エディターなどで均一かつ完璧に動作します。HoorayUnity。

すべて良い。しかし、「画面上」だけを描画したい場合はどうでしょうか。

つまり、ユーザーから「画面上」でスワイプ/タッチ/描画したいということです。 (たとえば、単に軌道カメラを操作する場合など)。カメラが走り回って動く通常の3Dゲームと同じです。

ワールドスペースのオブジェクトでの指の位置は必要ありません。抽象的な「指の動き」(つまりガラス上の位置)が必要なだけです。 。

その後、どのコライダーを使用しますか?コライダーなしでできますか?そのため、コライダーを追加するのは大変なことです。

これは何ですか

私はある種のフラットコライダーを作成し、実際にカメラの下に取り付けます。したがって、カメラの錐台に座って、画面を完全に覆います。

enter image description here

(コードの場合、ScreenToWorldPointを使用する必要はないので、例Bのようにコードを使用してください-非常にシンプルで、完全に機能します。)

私の質問、私が説明する「アンダーカメラコルディア」を使用する必要があるのは少し奇妙に思われます。ガラスに触れるだけです。

ここでの取引は何ですか?

(注-今日の実際のプロジェクトでは使用できないUnityの古代の「タッチ」システムに関する質問には答えないでください。レガシーアプローチを使用して.UIを無視することはできません。)


コードサンプルA-シーンオブジェクトに描画します。 ScreenToWorldPointを使用します。

 using UnityEngine;
 using System.Collections;
 using UnityEngine.EventSystems;

 public class FingerMove:MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
 {
     public void OnPointerDown (PointerEventData data)
     {
         Debug.Log("FINGER DOWN");
         prevPointWorldSpace =
                 theCam.ScreenToWorldPoint( data.position );
     }

     public void OnDrag (PointerEventData data)
     {
         thisPointWorldSpace =
                theCam.ScreenToWorldPoint( data.position );
         realWorldTravel =
                thisPointWorldSpace - prevPointWorldSpace;
         _processRealWorldtravel();
         prevPointWorldSpace = thisPointWorldSpace;
     }

     public void OnPointerUp (PointerEventData data)
     {
         Debug.Log("clear finger...");
     }

コードサンプルB ...ユーザーがデバイスのガラススクリーンで行うことだけに関心があります。ここでさらに簡単:

 using UnityEngine;
 using System.Collections;
 using UnityEngine.EventSystems;

 public class FingerMove:MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
 {
     private Vector2 prevPoint;
     private Vector2 newPoint;
     private Vector2 screenTravel;

     public void OnPointerDown (PointerEventData data)
     {
         Debug.Log("FINGER DOWN");
         prevPoint = data.position;
     }

     public void OnDrag (PointerEventData data)
     {
         newPoint = data.position;
         screenTravel = newPoint - prevPoint;
         prevPoint = newPoint;
         _processSwipe();
     }

     public void OnPointerUp (PointerEventData data)
     {
         Debug.Log("FINEGR UP...");
     }

     private void _processSwipe()
     {
         // your code here
         Debug.Log("screenTravel left-right.. " + screenTravel.x.ToString("f2"));
     }
 }

1 Unityを初めて使用する場合は、そのステップで、「描画」というレイヤーを作成してください。物理学の設定では、「描画」は何も操作しません。レイキャスターのステップ2では、レイヤーを「描画」に設定するだけです。

18
Fattie

これから投稿する質問と回答は、かなり意見に基づいているようです。それでも私はできる限り最善の答えをします。

画面上のポインターイベントを検出しようとしている場合、オブジェクトで画面を表現することに問題はありません。あなたのケースでは、3Dコライダーを使用してカメラの錐台全体をカバーします。ただし、画面全体をカバーする2D UIオブジェクトを使用して、Unityでこれを行うネイティブな方法があります。画面は2Dオブジェクトで最もよく表現できます。私にとっては、これは自然なやり方のようです。

私はこの目的のために一般的なコードを使用します:

public class Screen : MonoSingleton<Screen>, IPointerClickHandler, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerDownHandler, IPointerUpHandler, IScrollHandler {
    private bool holding = false;
    private PointerEventData lastPointerEventData;

    #region Events
    public delegate void PointerEventHandler(PointerEventData data);

    static public event PointerEventHandler OnPointerClick = delegate { };

    static public event PointerEventHandler OnPointerDown = delegate { };
    /// <summary> Dont use delta data as it will be wrong. If you are going to use delta, use OnDrag instead. </summary>
    static public event PointerEventHandler OnPointerHold = delegate { };
    static public event PointerEventHandler OnPointerUp = delegate { };

    static public event PointerEventHandler OnBeginDrag = delegate { };
    static public event PointerEventHandler OnDrag = delegate { };
    static public event PointerEventHandler OnEndDrag = delegate { };
    static public event PointerEventHandler OnScroll = delegate { };
    #endregion

    #region Interface Implementations
    void IPointerClickHandler.OnPointerClick(PointerEventData e) {
        lastPointerEventData = e;
        OnPointerClick(e);
    }

    // And other interface implementations, you get the point
    #endregion

    void Update() {
        if (holding) {
            OnPointerHold(lastPointerEventData);
        }
    }
}

Screenはシングルトンです。これは、ゲームのコンテキストでは画面が1つしかないためです。オブジェクト(カメラなど)は、そのポインターイベントをサブスクライブし、それに応じて自分自身を配置します。これにより、単一の責任が損なわれることもありません。

これを、いわゆるガラス(画面の表面)を表すオブジェクトに追加するときに使用します。 UIのボタンが画面から飛び出すと考えると、その下にガラスがあります。このため、グラスはCanvasの最初の子である必要があります。もちろん、Canvasは、意味をなすために画面スペースにレンダリングする必要があります。

ここでのハックの1つは、意味のないImageコンポーネントをガラスに追加して、イベントを受け取ることです。これは、ガラスのレイキャストターゲットのように機能します。

HierarchyInspector

InputInput.touchesなど)。このガラスオブジェクトを実装します。これは、すべてのUpdate呼び出しで入力が変更されたかどうかをチェックするように機能します。これはポーリングベースのアプローチのようですが、上記はイベントベースのアプローチです。

あなたの質問は、Inputクラスを使用して正当化する方法を探しているようです。私見、自分のために難しくしないでください。機能するものを使用します。そして、Unityは完璧ではないという事実を受け入れてください。

4
Gökhan Kurt

まず、OnPointerDown関数を使用してオブジェクトのクリックを検出する_3_の方法があることを理解する必要があります。

1OnPointerDown関数でクリックを検出するには、UIコンポーネントが必要です。これは、他の同様のUIイベントに適用されます。

2。2D/Sprite GameObjectでOnPointerDown関数を使用してクリックを検出する別の方法は、_Physics2DRaycaster_をカメラにアタッチし、次にOnPointerDownをアタッチすることですクリックすると呼び出されます。 2D Colliderをアタッチする必要があることに注意してください。

3。これがコライダーのない3Dオブジェクトである場合2Dコライダーの場合、PhysicsRaycasterをアタッチする必要がありますOnPointerDown関数を呼び出すためにカメラに送信します。

画面を覆う大きなコライダーや2Dコライダーを使用するよりも、最初の方法でこれを行う方が合理的です。あなたがしなければならないことは、Canvas、Panel GameObjectを作成し、画面全体に広がるImageコンポーネントをそれにアタッチすることです。

.UIを深刻な解決策として使用しているとは思えません。大きなゲームをやっていて、すべてのUI(つまり、ボタン、メニューなど)を実行しているチームをリードしていると想像してください。私は歩行ロボットをやっているチームを率いています。突然、「ああ、ちなみに、タッチ( "!")は処理できません。UIをドロップしてください。パネル、実行中のすべての操作の下に置くことを忘れないでください。あなたが交換するすべてのキャンバスまたはカメラに1つ-そしてその情報を私に返しますOK!」 :)私はそれがただばかげていることを意味します。本質的に言うことはできません:「ああ、Unityはタッチを処理しません」

あなたがそれを説明した方法のようにそれほど難しいことではありません。 CanvasPanelImageを作成できる長いコードを記述できます。画像のアルファを_0_に変更します。あなたがしなければならないのは、そのコードをカメラまたは空のゲームオブジェクトにアタッチすることだけで、プレイモードでこれをすべて自動的に実行します。

画面上でイベントを受信するすべてのGameObjectをサブスクライブし、_ExecuteEvents.Execute_を使用して、そのGameObjectに接続されているスクリプト内のすべてのインターフェイスにイベントを送信します。

たとえば、以下のサンプルコードは、OnPointerDownイベントをtargetという名前のGameObjectに送信します。

_ExecuteEvents.Execute<IPointerDownHandler>(target,
                              eventData,
                              ExecuteEvents.pointerDownHandler);
_

あなたが遭遇する問題

非表示のImageコンポーネントは、他のUIまたはゲームオブジェクトがレイキャストを受信するのをブロックします。これがここでの最大の問題です。

ソリューション

ブロッキングの問題が発生するため、画像のキャンバスをすべての上に配置することをお勧めします。これにより、他のすべてのUI/GameObjectを100ブロックしていることを確認できます。 _Canvas.sortingOrder = 12;_がこれを支援します。

画像からOnPointerDownなどのイベントを検出するたびに、手動でOnPointerDownイベントをImageの下の他のすべてのUI/GameObjectsに再送信します。

まず、GraphicRaycaster(UI)、_Physics2DRaycaster_(2D collider)、PhysicsRaycaster(3D Collider)を使用してレイキャストをスローし、結果をListに格納します。

次に、リストの結果をループし、次のコマンドを使用して結果に人工イベントを送信することにより、受け取ったイベントを再送信します。

_ExecuteEvents.Execute<IPointerDownHandler>(currentListLoop,
                              eventData,
                              ExecuteEvents.pointerDownHandler);
_

あなたが遭遇する他の問題

Toggleを使用して、GraphicRaycasterコンポーネントのエミュレートイベントを送信することはできません。これはUnityでは バグ です。これに気づくのに2日かかりました。

また、偽のスライダー移動イベントをSliderコンポーネントに送信できませんでした。これがバグかどうかわかりません。

上記の問題の他に、これを実装することができました。 3の部分で提供されます。フォルダを作成し、すべてのスクリプトをその中に配置するだけです。

[〜#〜] scripts [〜#〜]

1_WholeScreenPointer.cs_-Canvas、GameObject、非表示のImage。これは、Imageが常に画面をカバーするように、すべての複雑な処理を行います。また、すべてのサブスクライブGameObjectにイベントを送信します。

_public class WholeScreenPointer : MonoBehaviour
{
    //////////////////////////////// SINGLETON BEGIN  ////////////////////////////////
    private static WholeScreenPointer localInstance;

    public static WholeScreenPointer Instance { get { return localInstance; } }
    public EventUnBlocker eventRouter;

    private void Awake()
    {
        if (localInstance != null && localInstance != this)
        {
            Destroy(this.gameObject);
        }
        else
        {
            localInstance = this;
        }
    }
    //////////////////////////////// SINGLETON END  ////////////////////////////////


    //////////////////////////////// SETTINGS BEGIN  ////////////////////////////////
    public bool simulateUIEvent = true;
    public bool simulateColliderEvent = true;
    public bool simulateCollider2DEvent = true;

    public bool hideWholeScreenInTheEditor = false;
    //////////////////////////////// SETTINGS END  ////////////////////////////////


    private GameObject hiddenCanvas;

    private List<GameObject> registeredGameobjects = new List<GameObject>();

    //////////////////////////////// USEFUL FUNCTIONS BEGIN  ////////////////////////////////
    public void registerGameObject(GameObject objToRegister)
    {
        if (!isRegistered(objToRegister))
        {
            registeredGameobjects.Add(objToRegister);
        }
    }

    public void unRegisterGameObject(GameObject objToRegister)
    {
        if (isRegistered(objToRegister))
        {
            registeredGameobjects.Remove(objToRegister);
        }
    }

    public bool isRegistered(GameObject objToRegister)
    {
        return registeredGameobjects.Contains(objToRegister);
    }

    public void enablewholeScreenPointer(bool enable)
    {
        hiddenCanvas.SetActive(enable);
    }
    //////////////////////////////// USEFUL FUNCTIONS END  ////////////////////////////////

    // Use this for initialization
    private void Start()
    {
        makeAndConfigWholeScreenPinter(hideWholeScreenInTheEditor);
    }

    private void makeAndConfigWholeScreenPinter(bool hide = true)
    {
        //Create and Add Canvas Component
        createCanvas(hide);

        //Add Rect Transform Component
        //addRectTransform();

        //Add Canvas Scaler Component
        addCanvasScaler();

        //Add Graphics Raycaster Component
        addGraphicsRaycaster();

        //Create Hidden Panel GameObject
        GameObject panel = createHiddenPanel(hide);

        //Make the Image to be positioned in the middle of the screen then fix its anchor
        stretchImageAndConfigAnchor(panel);

        //Add EventForwarder script
        addEventForwarder(panel);

        //Add EventUnBlocker
        addEventRouter(panel);

        //Add EventSystem and Input Module
        addEventSystemAndInputModule();
    }

    //Creates Hidden GameObject and attaches Canvas component to it
    private void createCanvas(bool hide)
    {
        //Create Canvas GameObject
        hiddenCanvas = new GameObject("___HiddenCanvas");
        if (hide)
        {
            hiddenCanvas.hideFlags = HideFlags.HideAndDontSave;
        }

        //Create and Add Canvas Component
        Canvas cnvs = hiddenCanvas.AddComponent<Canvas>();
        cnvs.renderMode = RenderMode.ScreenSpaceOverlay;
        cnvs.pixelPerfect = false;

        //Set Cavas sorting order to be above other Canvas sorting order
        cnvs.sortingOrder = 12;

        cnvs.targetDisplay = 0;

        //Make it child of the GameObject this script is attached to
        hiddenCanvas.transform.SetParent(gameObject.transform);
    }

    private void addRectTransform()
    {
        RectTransform rctrfm = hiddenCanvas.AddComponent<RectTransform>();
    }

    //Adds CanvasScaler component to the Canvas GameObject 
    private void addCanvasScaler()
    {
        CanvasScaler cvsl = hiddenCanvas.AddComponent<CanvasScaler>();
        cvsl.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        cvsl.referenceResolution = new Vector2(800f, 600f);
        cvsl.matchWidthOrHeight = 0.5f;
        cvsl.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
        cvsl.referencePixelsPerUnit = 100f;
    }

    //Adds GraphicRaycaster component to the Canvas GameObject 
    private void addGraphicsRaycaster()
    {
        GraphicRaycaster grcter = hiddenCanvas.AddComponent<GraphicRaycaster>();
        grcter.ignoreReversedGraphics = true;
        grcter.blockingObjects = GraphicRaycaster.BlockingObjects.None;
    }

    //Creates Hidden Panel and attaches Image component to it
    private GameObject createHiddenPanel(bool hide)
    {
        //Create Hidden Panel GameObject
        GameObject hiddenPanel = new GameObject("___HiddenPanel");
        if (hide)
        {
            hiddenPanel.hideFlags = HideFlags.HideAndDontSave;
        }

        //Add Image Component to the hidden panel
        Image pnlImg = hiddenPanel.AddComponent<Image>();
        pnlImg.Sprite = null;
        pnlImg.color = new Color(1, 1, 1, 0); //Invisible
        pnlImg.material = null;
        pnlImg.raycastTarget = true;

        //Make it child of HiddenCanvas GameObject
        hiddenPanel.transform.SetParent(hiddenCanvas.transform);
        return hiddenPanel;
    }

    //Set Canvas width and height,to matach screen width and height then set anchor points to the corner of canvas.
    private void stretchImageAndConfigAnchor(GameObject panel)
    {
        Image pnlImg = panel.GetComponent<Image>();

        //Reset postion to middle of the screen
        pnlImg.rectTransform.anchoredPosition3D = new Vector3(0, 0, 0);

        //Stretch the Image so that the whole screen is totally covered
        pnlImg.rectTransform.anchorMin = new Vector2(0, 0);
        pnlImg.rectTransform.anchorMax = new Vector2(1, 1);
        pnlImg.rectTransform.pivot = new Vector2(0.5f, 0.5f);
    }

    //Adds EventForwarder script to the Hidden Panel GameObject 
    private void addEventForwarder(GameObject panel)
    {
        EventForwarder evnfwdr = panel.AddComponent<EventForwarder>();
    }

    //Adds EventUnBlocker script to the Hidden Panel GameObject 
    private void addEventRouter(GameObject panel)
    {
        EventUnBlocker evtrtr = panel.AddComponent<EventUnBlocker>();
        eventRouter = evtrtr;
    }

    //Add EventSystem
    private void addEventSystemAndInputModule()
    {
        //Check if EventSystem exist. If it does not create and add it
        EventSystem eventSys = FindObjectOfType<EventSystem>();
        if (eventSys == null)
        {
            GameObject evObj = new GameObject("EventSystem");
            EventSystem evs = evObj.AddComponent<EventSystem>();
            evs.firstSelectedGameObject = null;
            evs.sendNavigationEvents = true;
            evs.pixelDragThreshold = 5;
            eventSys = evs;
        }

        //Check if StandaloneInputModule exist. If it does not create and add it
        StandaloneInputModule sdlIpModl = FindObjectOfType<StandaloneInputModule>();
        if (sdlIpModl == null)
        {
            sdlIpModl = eventSys.gameObject.AddComponent<StandaloneInputModule>();
            sdlIpModl.horizontalAxis = "Horizontal";
            sdlIpModl.verticalAxis = "Vertical";
            sdlIpModl.submitButton = "Submit";
            sdlIpModl.cancelButton = "Cancel";
            sdlIpModl.inputActionsPerSecond = 10f;
            sdlIpModl.repeatDelay = 0.5f;
            sdlIpModl.forceModuleActive = false;
        }
    }

    /*
     Forwards Handler Event to every GameObject that implements  IDragHandler, IPointerDownHandler, IPointerUpHandler interface
     */

    public void forwardDragEvent(PointerEventData eventData)
    {
        //Route and send the event to UI and Colliders
        for (int i = 0; i < registeredGameobjects.Count; i++)
        {
            ExecuteEvents.Execute<IDragHandler>(registeredGameobjects[i],
                                    eventData,
                                    ExecuteEvents.dragHandler);
        }

        //Route and send the event to UI and Colliders
        eventRouter.routeDragEvent(eventData);
    }

    public void forwardPointerDownEvent(PointerEventData eventData)
    {
        //Send the event to all subscribed scripts
        for (int i = 0; i < registeredGameobjects.Count; i++)
        {
            ExecuteEvents.Execute<IPointerDownHandler>(registeredGameobjects[i],
                              eventData,
                              ExecuteEvents.pointerDownHandler);
        }

        //Route and send the event to UI and Colliders
        eventRouter.routePointerDownEvent(eventData);
    }

    public void forwardPointerUpEvent(PointerEventData eventData)
    {
        //Send the event to all subscribed scripts
        for (int i = 0; i < registeredGameobjects.Count; i++)
        {
            ExecuteEvents.Execute<IPointerUpHandler>(registeredGameobjects[i],
                    eventData,
                    ExecuteEvents.pointerUpHandler);
        }

        //Route and send the event to UI and Colliders
        eventRouter.routePointerUpEvent(eventData);
    }
}
_

2_EventForwarder.cs_-非表示のImageからイベントを受け取り、それを渡します_WholeScreenPointer.cs_スクリプトに追加して処理します。

_public class EventForwarder : MonoBehaviour, IDragHandler, IPointerDownHandler, IPointerUpHandler
{
    WholeScreenPointer wcp = null;
    void Start()
    {
        wcp = WholeScreenPointer.Instance;
    }

    public void OnDrag(PointerEventData eventData)
    {
        wcp.forwardDragEvent(eventData);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        wcp.forwardPointerDownEvent(eventData);
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        wcp.forwardPointerUpEvent(eventData);
    }
}
_

3_EventUnBlocker.cs_-非表示のImageが送信することでブロックしている光線のブロックを解除しますその上のオブジェクトへの偽のイベント。 UI、2D、または3Dコライダーである。

_public class EventUnBlocker : MonoBehaviour
{
    List<GraphicRaycaster> grRayCast = new List<GraphicRaycaster>(); //UI
    List<Physics2DRaycaster> phy2dRayCast = new List<Physics2DRaycaster>(); //Collider 2D (Sprite Renderer)
    List<PhysicsRaycaster> phyRayCast = new List<PhysicsRaycaster>(); //Normal Collider(3D/Mesh Renderer)

    List<RaycastResult> resultList = new List<RaycastResult>();

    //For Detecting button click and sending fake Button Click to UI Buttons
    Dictionary<int, GameObject> pointerIdToGameObject = new Dictionary<int, GameObject>();

    // Use this for initialization
    void Start()
    {

    }

    public void sendArtificialUIEvent(Component grRayCast, PointerEventData eventData, PointerEventType evType)
    {
        //Route to all Object in the RaycastResult
        for (int i = 0; i < resultList.Count; i++)
        {
            /*Do something if it is NOT this GameObject. 
             We don't want any other detection on this GameObject
             */

            if (resultList[i].gameObject != this.gameObject)
            {
                //Check if this is UI
                if (grRayCast is GraphicRaycaster)
                {
                    //Debug.Log("UI");
                    routeEvent(resultList[i], eventData, evType, true);
                }

                //Check if this is Collider 2D/SpriteRenderer
                if (grRayCast is Physics2DRaycaster)
                {
                    //Debug.Log("Collider 2D/SpriteRenderer");
                    routeEvent(resultList[i], eventData, evType, false);
                }

                //Check if this is Collider/MeshRender
                if (grRayCast is PhysicsRaycaster)
                {
                    //Debug.Log("Collider 3D/Mesh");
                    routeEvent(resultList[i], eventData, evType, false);
                }
            }
        }
    }

    //Creates fake PointerEventData that will be used to make PointerEventData for the callback functions
    PointerEventData createEventData(RaycastResult rayResult)
    {
        PointerEventData fakeEventData = new PointerEventData(EventSystem.current);
        fakeEventData.pointerCurrentRaycast = rayResult;
        return fakeEventData;
    }

    private void routeEvent(RaycastResult rayResult, PointerEventData eventData, PointerEventType evType, bool isUI = false)
    {
        bool foundKeyAndValue = false;

        GameObject target = rayResult.gameObject;

        //Make fake GameObject target
        PointerEventData fakeEventData = createEventData(rayResult);


        switch (evType)
        {
            case PointerEventType.Drag:

                //Send/Simulate Fake OnDrag event
                ExecuteEvents.Execute<IDragHandler>(target, fakeEventData,
                          ExecuteEvents.dragHandler);
                break;

            case PointerEventType.Down:

                //Send/Simulate Fake OnPointerDown event
                ExecuteEvents.Execute<IPointerDownHandler>(target,
                         fakeEventData,
                          ExecuteEvents.pointerDownHandler);

                //Code Below is for UI. break out of case if this is not UI
                if (!isUI)
                {
                    break;
                }
                //Prepare Button Click. Should be sent in the if PointerEventType.Up statement
                Button buttonFound = target.GetComponent<Button>();

                //If pointerId is not in the dictionary add it
                if (buttonFound != null)
                {
                    if (!dictContains(eventData.pointerId))
                    {
                        dictAdd(eventData.pointerId, target);
                    }
                }

                //Bug in Unity with GraphicRaycaster  and Toggle. Have to use a hack below
                //Toggle Toggle component
                Toggle toggle = null;
                if ((target.name == "Checkmark" || target.name == "Label") && toggle == null)
                {
                    toggle = target.GetComponentInParent<Toggle>();
                }

                if (toggle != null)
                {
                    //Debug.LogWarning("Toggled!: " + target.name);
                    toggle.isOn = !toggle.isOn;
                    //Destroy(toggle.gameObject);
                }
                break;

            case PointerEventType.Up:

                //Send/Simulate Fake OnPointerUp event
                ExecuteEvents.Execute<IPointerUpHandler>(target,
                        fakeEventData,
                        ExecuteEvents.pointerUpHandler);

                //Code Below is for UI. break out of case if this is not UI
                if (!isUI)
                {
                    break;
                }

                //Send Fake Button Click if requirement is met
                Button buttonPress = target.GetComponent<Button>();

                /*If pointerId is in the dictionary, check 

                 */
                if (buttonPress != null)
                {
                    if (dictContains(eventData.pointerId))
                    {
                        //Check if GameObject matches too. If so then this is a valid Click
                        for (int i = 0; i < resultList.Count; i++)
                        {
                            GameObject tempButton = resultList[i].gameObject;
                            if (tempButton != this.gameObject && dictContains(eventData.pointerId, tempButton))
                            {
                                foundKeyAndValue = true;
                                //Debug.Log("Button ID and GameObject Match! Sending Click Event");

                                //Send/Simulate Fake Click event to the Button
                                ExecuteEvents.Execute<IPointerClickHandler>(tempButton,
                                      new PointerEventData(EventSystem.current),
                                      ExecuteEvents.pointerClickHandler);
                            }
                        }
                    }
                }
                break;
        }

        //Remove pointerId since it exist 
        if (foundKeyAndValue)
        {
            dictRemove(eventData.pointerId);
        }
    }

    void routeOption(PointerEventData eventData, PointerEventType evType)
    {
        UpdateRaycaster();
        if (WholeScreenPointer.Instance.simulateUIEvent)
        {
            //Loop Through All GraphicRaycaster(UI) and throw Raycast to each one
            for (int i = 0; i < grRayCast.Count; i++)
            {
                //Throw Raycast to all UI elements in the position(eventData)
                grRayCast[i].Raycast(eventData, resultList);
                sendArtificialUIEvent(grRayCast[i], eventData, evType);
            }
            //Reset Result
            resultList.Clear();
        }

        if (WholeScreenPointer.Instance.simulateCollider2DEvent)
        {
            //Loop Through All Collider 2D (Sprite Renderer) and throw Raycast to each one
            for (int i = 0; i < phy2dRayCast.Count; i++)
            {
                //Throw Raycast to all UI elements in the position(eventData)
                phy2dRayCast[i].Raycast(eventData, resultList);
                sendArtificialUIEvent(phy2dRayCast[i], eventData, evType);
            }
            //Reset Result
            resultList.Clear();
        }

        if (WholeScreenPointer.Instance.simulateColliderEvent)
        {
            //Loop Through All Normal Collider(3D/Mesh Renderer) and throw Raycast to each one
            for (int i = 0; i < phyRayCast.Count; i++)
            {
                //Throw Raycast to all UI elements in the position(eventData)
                phyRayCast[i].Raycast(eventData, resultList);
                sendArtificialUIEvent(phyRayCast[i], eventData, evType);
            }
            //Reset Result
            resultList.Clear();
        }
    }

    public void routeDragEvent(PointerEventData eventData)
    {
        routeOption(eventData, PointerEventType.Drag);
    }

    public void routePointerDownEvent(PointerEventData eventData)
    {
        routeOption(eventData, PointerEventType.Down);
    }

    public void routePointerUpEvent(PointerEventData eventData)
    {
        routeOption(eventData, PointerEventType.Up);
    }

    public void UpdateRaycaster()
    {
        convertToList(FindObjectsOfType<GraphicRaycaster>(), grRayCast);
        convertToList(FindObjectsOfType<Physics2DRaycaster>(), phy2dRayCast);
        convertToList(FindObjectsOfType<PhysicsRaycaster>(), phyRayCast);
    }

    //To avoid ToList() function
    void convertToList(GraphicRaycaster[] fromComponent, List<GraphicRaycaster> toComponent)
    {
        //Clear and copy new Data
        toComponent.Clear();
        for (int i = 0; i < fromComponent.Length; i++)
        {
            toComponent.Add(fromComponent[i]);
        }
    }

    //To avoid ToList() function
    void convertToList(Physics2DRaycaster[] fromComponent, List<Physics2DRaycaster> toComponent)
    {
        //Clear and copy new Data
        toComponent.Clear();
        for (int i = 0; i < fromComponent.Length; i++)
        {
            toComponent.Add(fromComponent[i]);
        }
    }

    //To avoid ToList() function
    void convertToList(PhysicsRaycaster[] fromComponent, List<PhysicsRaycaster> toComponent)
    {
        //Clear and copy new Data
        toComponent.Clear();
        for (int i = 0; i < fromComponent.Length; i++)
        {
            toComponent.Add(fromComponent[i]);
        }
    }

    //Checks if object is in the dictionary
    private bool dictContains(GameObject obj)
    {
        return pointerIdToGameObject.ContainsValue(obj);
    }

    //Checks if int is in the dictionary
    private bool dictContains(int pointerId)
    {
        return pointerIdToGameObject.ContainsKey(pointerId);
    }

    //Checks if int and object is in the dictionary
    private bool dictContains(int pointerId, GameObject obj)
    {
        return (pointerIdToGameObject.ContainsKey(pointerId) && pointerIdToGameObject.ContainsValue(obj));
    }

    //Adds pointerId and its value to dictionary
    private void dictAdd(int pointerId, GameObject obj)
    {
        pointerIdToGameObject.Add(pointerId, obj);
    }

    //Removes pointerId and its value from dictionary
    private void dictRemove(int pointerId)
    {
        pointerIdToGameObject.Remove(pointerId);
    }

    public enum PointerEventType
    {
        Drag, Down, Up
    }
}
_

使用法

1。空のゲームオブジェクトまたはカメラにWholeScreenPointerスクリプトをアタッチします。

2シーン内のイベントを受信するには、任意のスクリプトにIDragHandlerIPointerDownHandlerIPointerUpHandlerを実装してから、WholeScreenPointer.Instance.registerGameObject(this.gameObject);を1回呼び出します。画面からのイベントはすべてそのスクリプトに送信されます。 OnDisable()関数で登録を解除することを忘れないでください。

たとえば、タッチイベントを受信する任意のGameObjectにTestをアタッチします。

_public class Test : MonoBehaviour, IDragHandler, IPointerDownHandler, IPointerUpHandler
{
    void Start()
    {
        //Register this GameObject so that it will receive events from WholeScreenPointer script
        WholeScreenPointer.Instance.registerGameObject(this.gameObject);
    }

    public void OnDrag(PointerEventData eventData)
    {
        Debug.Log("Dragging: ");
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        Debug.Log("Pointer Down: ");
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        Debug.Log("Pointer Up: ");
    }

    void OnDisable()
    {
        WholeScreenPointer.Instance.unRegisterGameObject(this.gameObject);
    }
}
_

[〜#〜]ノート[〜#〜]

画面上の任意の場所でイベントを受信する場合は、WholeScreenPointer.Instance.registerGameObject(this.gameObject);を呼び出すだけです。現在のオブジェクトからイベントを受け取るだけの場合は、これを呼び出す必要はありません。その場合、複数のイベントを受け取ります。

その他の重要な機能:

WholeScreenイベントを有効にする-WholeScreenPointer.Instance.enablewholeScreenPointer(true);

WholeScreenイベントを無効にする-WholeScreenPointer.Instance.enablewholeScreenPointer(false);最後に、これをさらに改善できます。

6
Programmer