2016-10-29 4 views
15

В Unity говорится, что вам нужно обнаружить прикосновение пальца (рисунок пальца) к чему-то в сцене.Использование подхода IPointerDownHandler от Unity3D, но с «целым экраном»

Единственный способ сделать это в современном Unity, очень просто:


Шаг 1. Поместите коллайдер на этот объект. («Земля» или что это может быть.)

Шаг 2. На вашей камере, инспектор панели, нажмите, чтобы добавить Physics Raycaster (2D или 3D, как это уместно).

Шаг 3. Просто используйте код, как в примере А ниже.

(Совет - не забудьте обеспечить есть более EventSystem ... иногда Unity добавляет его автоматически, иногда нет!)


Потрясающе, не может быть проще. Unity, наконец, правильно обрабатывает un/распространение через слой пользовательского интерфейса. Работает равномерно и безупречно на рабочем столе, устройствах, редакторах и т. Д. И т. Д. Hooray Unity.

Все в порядке. Но что, если вы хотите нарисовать только «на экране»?

Таким образом, вы хотите, просто, щелкнуть/коснуться/сделать рисунок от пользователя «на экране». (Например, просто для управления камерой на орбите, скажем.) Так же, как в любой обычной 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; 
     _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")); 
    } 
} 

Если вы только новичок в Unity: на этой стадии весьма вероятно, сделать его слой, называемый сказать «Draw»; в физических настройках «Ничья» взаимодействует ни с чем; на втором шаге с Raycaster просто установите слой в «Draw».

+0

Итак, в вашем явном варианте использования вы хотите использовать весь экран и избегать взаимодействия с пользовательским интерфейсом, не используя поддельный коллайдер. Правильно ли я понял? –

+0

Почему панель UI или Input.touches ошибочны? Может быть, объясните, почему вы не хотите, чтобы те помогли. – Everts

+0

HI Ev, input.touch абсолютно бесполезен, он не размножается через интерфейс пользователя. (Вся основная и самая известная проблема Единства заключается в том, что они полностью забыли блокировать события касания от распространения через Unity.UI. Это привело к миллиардам человеко-часов программирования, пытающихся обойти эту проблему, хе-хе (пример zillions of QA с той эпохи] (http://answers.unity3d.com/questions/784617/how-do-i-block-touch-events-from-propagating-throu.html). Единство, наконец, зафиксировало это с помощью PhysicalRaycaster, который мы все используем теперь как самый основной элемент Unity.) Что касается ... – Fattie

ответ

2

Вопрос и ответ, который я собираюсь опубликовать, похоже на мнение, основанное на мнениях. Тем не менее я собираюсь ответить как можно лучше.

Если вы пытаетесь обнаружить события указателя на экране, нет ничего плохого в представлении экрана с объектом. В вашем случае вы используете 3D-коллайдер, чтобы покрыть всю усечку камеры. Тем не менее, есть собственный способ сделать это в Unity, используя 2D-объект UI, который охватывает весь экран. Экран может быть лучше всего представлен 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 одноэлементен, потому что есть только один экран в контексте игры. Объекты (например, камера) подписываются на события указателя и организуют их соответственно. Это также сохраняет целостность одной ответственности.

Вы использовали бы это как дополнение к объекту, который представляет собой так называемое стекло (поверхность экрана). Если вы думаете, что кнопки в пользовательском интерфейсе выходят из экрана, стекло будет под ними. Для этого стекло должно быть первым ребенком Canvas. Конечно, Canvas должен отображаться на экране, чтобы это имело смысл.

Один взломанный здесь, что не имеет смысла, это добавить невидимый компонент Image к стеклу, чтобы он получал события. Это действует как расистская цель стекла.

Hierarchy Inspector

Вы также можете использовать Input (Input.touches и т.д.), чтобы реализовать этот стеклянный объект. Он будет работать как проверка, если вход изменился в каждом вызове Update. Это похоже на подход, основанный на опросах, в то время как вышеупомянутый подход основан на событиях.

Ваш вопрос выглядит как если бы вы искали способ оправдать использование класса Input. ИМХО, Не делай это сложнее для себя. Используйте то, что работает. И соглашайтесь с тем, что Единство не совершенно.

+0

Я также могу включить полный код для этого класса «Экран». Кроме того, вы, вероятно, не хотите называть его «Экран», потому что он будет конфликтовать с Unity. –

+0

Эй, @ Gökhan - просто чтобы быть понятным, вы предлагаете добавить коллайдер, но сделайте это в системе .UI, а не как 3D-коллайдер под камерой. – Fattie

+0

Было бы лучше использовать целую отдельную систему Холста * только для этой цели *, Гёхан. (Вы можете даже запустить его программно, если хотите.) Действительно, лучше держать его на отдельной камере. Кажется, стыдно иметь концепцию, что вы «всегда должны добавить это под своим обычным .UI и не забудьте сделать это внизу» ... – Fattie

3

Прежде всего, вы должны понимать, что есть только 3 способы обнаружения нажмите на объект с помощью функции OnPointerDown:

.Вы нужен компонент пользовательского интерфейса для того, чтобы обнаружить кнопку с OnPointerDown функция. Это относится к другим аналогичным событиям пользовательского интерфейса.

.Another метод обнаружения щелчок с OnPointerDown функции на 2D/Sprite GameObject это присоединить Physics2DRaycaster к камере, а затем OnPointerDown будет вызываться, когда она нажата. Обратите внимание, что к нему должен быть прикреплен 2D-коллайдер .

.Если это 3D объект с коллайдера не 2D коллайдер, вы должны быть PhysicsRaycaster прикреплены к камере для того, чтобы функция OnPointerDown называться.

Выполнение этого с помощью первого метода представляется более разумным вместо того, чтобы иметь большой коллайдер или 2D-коллайдер, покрывающий экран. Все, что вы делаете, это создать Canvas, Panel GameObject и подключить компонент Image, который будет растягиваться по всему экрану.

Чувак, я просто не вижу, используя .ui как серьезное решение: представьте себе, что мы делает большую игру, и вы ведущую команду, которая делает все UI (я имею в виду кнопки, меню и все). Я веду группу, занимающуюся ходьбой роботов. Я вдруг говорю вам: «О, кстати, я не могу справиться с прикосновением («! »), Не могли бы вы зайти в UI.Panel, не забудьте оставить его под все, что вы делаете, о и поместите один на все/все кассеты или камеры, которые вы меняете, и передайте эту информацию мне в порядке! " :) I означает, что это просто глупо. В принципе нельзя сказать: «Ох, Единство не ручка касания»

Не очень сложно, как вы описали его. Вы можете написать длинный код, который сможет создать Canvas, Panel и Image. Измените изображение alpha на 0. Все, что вам нужно сделать, это прикрепить этот код к Камере или пустой GameObject, и он автоматически выполнит все это для вас в режиме воспроизведения.

Сделать каждый объект GameObject, который хочет получить событие на экране, подписаться на него, а затем использовать ExecuteEvents.Execute для отправки события всем интерфейсам в скрипте, прикрепленном к этому GameObject.

Например, пример кода ниже отправит событие OnPointerDown в GameObject под названием target.

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

Проблема вы столкнетесь:

Скрытое Image компонент будет блокировать другой интерфейс или GameObject от получения raycast. Это самая большая проблема здесь.

Решение:

Поскольку это вызовет некоторые проблемы блокировки, то лучше сделать канву изображения, чтобы быть на вершине всего. Это позволит убедиться, что теперь 100 блокирует все другие UI/GameObject. Canvas.sortingOrder = 12; должен помочь нам сделать это.

Каждый раз, когда мы обнаруживаем такие события, как OnPointerDown от изображения, мы вручную отправить повторно отправить OnPointerDown событие для всех других UI/геймобжектов под Image.

Прежде всего, мы бросаем raycast с GraphicRaycaster (UI), Physics2DRaycaster (2D коллайдера), PhysicsRaycaster (3D коллайдер) и сохранить результат в List.

Теперь мы перебираем результат в списке и отправить событие, которое мы получили, отправив искусственное событие результатов с:

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

Другие проблемы вы столкнетесь:

Вы не смогут отправлять события эмулирования на компонент Toggle с GraphicRaycaster. Это bug в Unity. Мне потребовалось 2 дня, чтобы понять это.

Также не удалось отправить событие перемещения поддельного слайдера на компонент Slider. Я не могу сказать, является ли это ошибкой или нет.

Помимо этих проблем, упомянутых выше, я смог реализовать это. Он поставляется в детали. Просто создайте папку и поместите в нее все скрипты.

SCRIPTS:

. 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); 
    } 
} 

. 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); 
    } 
} 

. 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 
    } 
} 

Использование:

.Attach WholeScreenPointer сценарий пустой GameObject или камеры.

.Чтобы получить какое-либо событие в сцене, просто реализовать IDragHandler, IPointerDownHandler, IPointerUpHandler в любом сценарии затем вызвать WholeScreenPointer.Instance.registerGameObject(this.gameObject); один раз. Любое событие с экрана теперь будет отправлено на этот скрипт. Не забудьте отменить регистрацию в функции OnDisable().

Например, прикрепить Test к любому GameObject вы хотите получать события прикосновения:

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); Наконец, это может быть улучшено более.

+0

Удивительная идея отправить их вперед! – Fattie

+0

Подождите - одна маленькая точка. Как я уже говорил Гёхану выше: вы знаете, как на панели вы используете невидимый образ, потому что Unity забыл сделать компонент Touchable. У нас есть ОБЩЕЕ ЛУЧШЕЕ РЕШЕНИЕ! stackoverflow.com/a/36892803/294884 Просто используйте «Touchable» в любом месте, где бы вы не использовали «невидимое изображение, потому что Unity забыл Touchable» – Fattie

+0

Я щелкал щедростью здесь, так как этот ответ настолько обширен, и осталось всего лишь несколько минут в щедрости, приветствует мужчин! – Fattie