unity game c# unity3d touch

c# - game - Usando el enfoque IPointerDownHandler de Unity3D, pero con "toda la pantalla"



unity touch count (2)

En Unity, diga que necesita detectar el toque con los dedos (dibujo con los dedos) en algo de la escena.

La única manera de hacer esto en la Unidad moderna, es muy simple :

Paso 1 Pon un colisionador en ese objeto. ("El suelo" o lo que sea.) 1

Paso 2. En su cámara, panel Inspector, haga clic para agregar un Physics Raycaster (2D o 3D, según corresponda).

Paso 3. Simplemente use el código como en el Ejemplo A a continuación.

(Sugerencia: no olvide asegurarse de que haya un sistema de eventos ... ¡a veces Unity agrega uno automáticamente, a veces no!)

Fantástico, no podría ser más fácil. Unity finalmente maneja la propagación / propagación correctamente a través de la capa UI. Funciona de manera uniforme y sin fallas en el escritorio, los dispositivos, el editor, etc.

Todo bien. Pero, ¿y si quieres dibujar solo "en la pantalla" ?

Por lo tanto, usted está queriendo, simplemente, deslizar / tocar / dibujar del usuario "en la pantalla". (Ejemplo, simplemente para operar una cámara orbital, por ejemplo). Así como en cualquier juego 3D común donde la cámara funciona y se mueve.

No desea la posición del dedo sobre algún objeto en el espacio del mundo, simplemente quiere "movimientos de dedo" abstractos (es decir, posición sobre el cristal).

¿Qué colisionador usas entonces? ¿Puedes hacerlo sin colisionador? Parece fatuo agregar un colisionador solo por esa razón.

Lo que hacemos es esto :

Acabo de hacer un colisionador plano de algún tipo, y en realidad lo coloco debajo de la cámara . Así que simplemente se sienta en el frustum de la cámara y cubre completamente la pantalla.

(Para el código, no hay necesidad de usar ScreenToWorldPoint, así que solo use el código como en el Ejemplo B: extremadamente simple, funciona perfectamente).

Mi pregunta, parece un poco extraño tener que usar el "más pequeño debajo de la cámara" que describo, solo para tocar el cristal.

¿Cuál es el problema aquí?

(Nota: no responda con el antiguo sistema de "toques" de Unity, que hoy en día no se puede utilizar para proyectos reales, no puede ignorar .UI utiliza el enfoque heredado)

Ejemplo de código A: dibujo en un objeto de escena. Utilice 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..."); }

Ejemplo de código B ... solo le importa lo que el usuario hace en la pantalla de cristal del dispositivo. Aún más fácil aquí:

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 Si solo eres nuevo en Unity: en ese paso es muy probable que sea una capa llamada "Draw"; en la configuración física, haga que "Draw" interactúe con nada; en el paso dos con el Raycaster solo establece la capa en "Dibujar".


En primer lugar, debe comprender que solo hay 3 formas de detectar el clic en un objeto con la función OnPointerDown :

1. Necesita un componente de UI para detectar el clic con la función OnPointerDown . Esto se aplica a otros eventos de interfaz de usuario similares.

2. Otro método para detectar un clic con la función OnPointerDown en un OnPointerDown 2D / Sprite es adjuntar Physics2DRaycaster a la cámara y luego se OnPointerDown a OnPointerDown cuando se haga clic en él. Tenga en cuenta que se debe adjuntar un Colisionador 2D .

3. Si este es un Objeto 3D con un Colisionador no Colisionador 2D , debe tener PhysicsRaycaster conectado a la cámara para que se pueda llamar a la función OnPointerDown .

Hacer esto con el primer método parece más razonable en lugar de tener un colisionador grande o un colisionador 2D que cubra la pantalla. Todo lo que debe hacer es crear un Canvas , Panel GameObject y adjuntar un componente de Image que se extienda por toda la pantalla.

Amigo, simplemente no veo usar .UI como una solución seria: imagina que estamos haciendo un gran juego y lideras un equipo que está haciendo toda la IU (me refiero a botones, menús y todo). Estoy liderando un equipo haciendo los robots andantes. De repente te digo "oh, por cierto, no puedo manejar el tacto ("! "), Podrías dejar caer una interfaz de usuario. Panel, no olvides mantenerlo debajo de todo lo que estás haciendo, oh y ponlo una en cualquier / todos los lienzos o cámaras con las que intercambies, y devuélveme esa información, ¡bien! " :) Quiero decir que es simplemente tonto. Esencialmente no se puede decir: "oh, la unidad no maneja el tacto"

No es tan difícil como lo describiste. Puede escribir un código largo que podrá crear un Canvas , un Panel y una Image . Cambia la imagen alfa a 0 . Todo lo que tienes que hacer es adjuntar ese código a la cámara o a un GameObject vacío y todo esto se realizará automáticamente en el modo de reproducción.

Haga que todos los GameObject que quieran recibir eventos en la pantalla se suscriban, luego use ExecuteEvents.Execute para enviar el evento a todas las interfaces en el script adjunto a ese GameObject.

Por ejemplo, el código de muestra a continuación enviará el evento OnPointerDown al GameObject llamado target.

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

Problema que se encontrará con :

El componente de Image oculto bloqueará a otra UI o GameObject para que no reciba Raycast. Este es el mayor problema aquí.

Solución :

Ya que causará algunos problemas de bloqueo, es mejor hacer que el Lienzo de la imagen esté encima de todo. Esto asegurará que ahora haya 100 bloqueando todas las demás UI / GameObject. Canvas.sortingOrder = 12; debería ayudarnos a hacer esto

Cada vez que detectamos un evento como OnPointerDown desde la imagen, enviaremos manualmente reenviar el evento OnPointerDown a todos los demás UI / GameObjects debajo de la Image .

En primer lugar, lanzamos un raycast con GraphicRaycaster (UI), Physics2DRaycaster (2D PhysicsRaycaster ), PhysicsRaycaster (3D Collider) y almacenamos el resultado en una List .

Ahora, repasamos el resultado en la Lista y reenviamos el evento que recibimos enviando un evento artificial a los resultados con:

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

Otros problemas con los que se encontrará :

No podrá enviar eventos de emulación en el componente Toggle con GraphicRaycaster . Este es un bug en la unidad. Me tomó 2 días darme cuenta de esto.

Tampoco fue capaz de enviar un evento de movimiento deslizante falso al componente Slider . No puedo decir si esto es un error o no.

Aparte de estos problemas mencionados anteriormente, pude implementar esto. Se presenta en 3 partes. Solo crea una carpeta y coloca todos los scripts en ellos.

ESCRITOS :

1 . WholeScreenPointer.cs : la parte principal del script que crea Canvas , GameObject y una Image oculta. Hace todo lo complicado para asegurarse de que la Image siempre cubra la pantalla. También envía eventos a todos los suscritos a 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 : simplemente recibe cualquier evento de la Image oculta y lo pasa al script WholeScreenPointer.cs para su procesamiento.

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 : EventUnBlocker.cs los rayos que bloquea la Image oculta al enviar un evento falso a cualquier objeto que se encuentre por encima de él. Ya sea UI, 2D o colisionador 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 } }

Uso

1. Conecte la WholeScreenPointer comandos WholeScreenPointer a un GameObject vacío o la cámara.

2. Para recibir cualquier evento en la escena, simplemente implemente IDragHandler , IPointerDownHandler , IPointerUpHandler en cualquier script y luego llame a WholeScreenPointer.Instance.registerGameObject(this.gameObject); una vez. Cualquier evento de la pantalla se enviará a ese script. No olvide OnDisable() el registro en la función OnDisable() .

Por ejemplo, adjunte Test a cualquier GameObject que quiera recibir eventos táctiles:

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

NOTA :

Solo necesita llamar a WholeScreenPointer.Instance.registerGameObject(this.gameObject); Si desea recibir eventos en cualquier lugar de la pantalla. Si solo desea recibir un evento del Objeto actual, entonces no tiene que llamar a esto. Si lo haces, recibirás múltiples eventos.

Otras funciones importantes:

Habilitar el evento WholeScreen - WholeScreenPointer.Instance.enablewholeScreenPointer(true);

Deshabilitar el evento WholeScreen - WholeScreenPointer.Instance.enablewholeScreenPointer(false); Finalmente, esto se puede mejorar más.


La pregunta y la respuesta que voy a publicar parecen bastante basadas en la opinión. Sin embargo voy a responder lo mejor que pueda.

Si está intentando detectar eventos de puntero en la pantalla, no hay nada de malo en representar la pantalla con un objeto. En su caso, utiliza un colisionador 3D para cubrir todo el frustum de la cámara. Sin embargo, hay una forma nativa de hacer esto en Unity, utilizando un objeto de UI 2D que cubre toda la pantalla. La pantalla se puede representar mejor mediante un objeto 2D. Para mí, esto parece una forma natural de hacerlo.

Yo uso un código genérico para este propósito:

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

La Screen es un singleton, porque solo hay una pantalla en el contexto del juego. Los objetos (como la cámara) se suscriben a sus eventos de puntero y se ordenan en consecuencia. Esto también mantiene intacta la única responsabilidad.

Lo usaría para agregarlo a un objeto que representa el llamado vidrio (superficie de la pantalla). Si crees que los botones de la interfaz de usuario están saliendo de la pantalla, el cristal estaría debajo de ellos. Para ello, el cristal tiene que ser el primer hijo del Canvas . Por supuesto, el Canvas debe representarse en el espacio de la pantalla para que tenga sentido.

Un truco aquí, que no tiene sentido es agregar un componente de Image invisible al vidrio, para que reciba eventos. Esto actúa como el objetivo de raycast del vidrio.

También puede usar Input ( Input.touches etc.) para implementar este objeto de vidrio. Funcionaría como verificación si la entrada cambiara en cada llamada de Update . Esto me parece un enfoque basado en encuestas, mientras que el anterior es un enfoque basado en eventos.

Su pregunta parece estar buscando una forma de justificar el uso de la clase de Input . En mi humilde opinión, no te lo pongas difícil. Usa lo que funciona. Y acepta el hecho de que la Unidad no es perfecta.