Horror OnPointerDown vs OnBeginDrag in Unity3D

I am concerned about the difference between OnPointerDown and OnBeginDrag in the one-finger motion code.

(In the latest Unity paradigm about using physics raycaster: so, finally, Unity will correctly ignore touching the user interface layer.

So, from 2015 you should do the following:

  1. Forget the crap of the traditional Input or Touches , which is pointless and doesn't work

  2. Add an empty game object with usually BoxCollider2D, probably larger than the screen. Make a layer called "Draw". Physics settings β€œDraw” doesn't interact with anything

  3. Just add 2D or 3D raycaster physics to your camera . The event masks the "Draw" layer.

enter image description here

Make a script as shown below and put it on.

(Tip - don't forget to just add an EventSystem to the scene. Ironically, Unity does not automatically do this for you in some situations, but Unity does it automatically for you in other situations, so it is annoying if you forget!)

But here is the problem .

OnPointerDown OnBeginDrag difference between using OnPointerDown and OnBeginDrag (and the corresponding end calls). (You can simply change the action in the following code example.)

Naturally, Unity gives no indication whatsoever; the following code perfectly rejects random captures, and also flawlessly ignores your user interface level (finally, thanks Unity!), but I'm not sure about the difference between the two approaches (we start dragging V. we start touching) and I just can’t find the logical difference between the two in unit testing.

What answer?

 /* general movement of something by a finger. */ using UnityEngine; using System.Collections; using UnityEngine.EventSystems; public class FingerMove:MonoBehaviour, IPointerDownHandler, IBeginDragHandler, IDragHandler, IPointerUpHandler, IEndDragHandler { public Transform moveThis; private Camera theCam; private FourLimits thingLimits; private Vector3 prevPointWorldSpace; private Vector3 thisPointWorldSpace; private Vector3 realWorldTravel; public void Awake() { theCam = Camera.main or whatever; } public void OnMarkersReady() // (would be EVENT DRIVEN for liveness) { thingLimits = Grid.liveMarkers. your motion limits } private int drawFinger; private bool drawFingerAlreadyDown; public void OnPointerDown (PointerEventData data) { Debug.Log(" P DOWN " +data.pointerId.ToString() ); } public void OnBeginDrag (PointerEventData data) { Debug.Log(" BEGIN DRAG " +data.pointerId.ToString() ); if (drawFingerAlreadyDown == true) { Debug.Log(" IGNORE THAT DOWN! " +data.pointerId.ToString() ); return; } drawFinger = data.pointerId; drawFingerAlreadyDown=true; prevPointWorldSpace = theCam.ScreenToWorldPoint( data.position ); } public void OnDrag (PointerEventData data) { Debug.Log(" ON DRAG " +data.pointerId.ToString() ); if (drawFingerAlreadyDown == false) { Debug.Log(" IGNORE THAT PHANTOM! " +data.pointerId.ToString() ); } if ( drawFinger != data.pointerId ) { Debug.Log(" IGNORE THAT DRAG! " +data.pointerId.ToString() ); return; } thisPointWorldSpace = theCam.ScreenToWorldPoint( data.position ); realWorldTravel = thisPointWorldSpace - prevPointWorldSpace; _processRealWorldtravel(); prevPointWorldSpace = thisPointWorldSpace; } public void OnEndDrag (PointerEventData data) { Debug.Log(" END DRAG " +data.pointerId.ToString() ); if ( drawFinger != data.pointerId ) { Debug.Log(" IGNORE THAT UP! " +data.pointerId.ToString() ); return; } drawFingerAlreadyDown = false; } public void OnPointerUp (PointerEventData data) { Debug.Log(" P UP " +data.pointerId.ToString() ); } private void _processRealWorldtravel() { if ( Grid. your pause concept .Paused ) return; // potential new position... Vector3 pot = moveThis.position + realWorldTravel; // almost always, squeeze to a limits box... // (whether the live screen size, or some other box) if (pot.x < thingLimits.left) pot.x = thingLimits.left; if (pot.y > thingLimits.top) pot.y = thingLimits.top; if (pot.x > thingLimits.right) pot.x = thingLimits.right; if (pot.y < thingLimits.bottom) pot.y = thingLimits.bottom; // kinematic ... moveThis.position = pot; // or // if pushing around physics bodies ... rigidbody.MovePosition(pot); } } 

And here is a convenient thing. Keep typing with the same thing for 3D scenes using a little-known but sophisticated

pointerCurrentRaycast

here's how ... pay attention to the excellent

 data.pointerCurrentRaycast.worldPosition 

call courtesy of Unity.

 public class FingerDrag .. for 3D scenes:MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler { public Transform moveMe; private Vector3 prevPointWorldSpace; private Vector3 thisPointWorldSpace; private Vector3 realWorldTravel; private int drawFinger; private bool drawFingerAlreadyDown; public void OnPointerDown (PointerEventData data) { if (drawFingerAlreadyDown == true) return; drawFinger = data.pointerId; drawFingerAlreadyDown=true; prevPointWorldSpace = data.pointerCurrentRaycast.worldPosition; // in this example we'll put it under finger control... moveMe.GetComponent<Rigidbody>().isKinematic = false; } public void OnDrag (PointerEventData data) { if (drawFingerAlreadyDown == false) return; if ( drawFinger != data.pointerId ) return; thisPointWorldSpace = data.pointerCurrentRaycast.worldPosition; realWorldTravel = thisPointWorldSpace - prevPointWorldSpace; _processRealWorldtravel(); prevPointWorldSpace = thisPointWorldSpace; } public void OnPointerUp (PointerEventData data) { if ( drawFinger != data.pointerId ) return; drawFingerAlreadyDown = false; moveMe.GetComponent<Rigidbody>().isKinematic = false; moveMe = null; } private void _processRealWorldtravel() { Vector3 pot = moveMe.position; pot.x += realWorldTravel.x; pot.y += realWorldTravel.y; moveMe.position = pot; } } 
+3
source share
2 answers

I want to start by saying that Input and Touches are not crappy. They were still useful and were the best way to test touch on mobile devices before OnPointerDown and OnBeginDrag . OnMouseDown() you can call crappy because it is not optimized for mobile devices. For a beginner who has just begun to learn Unity, Input and Touches are their parameters.

As for your question, OnPointerDown and OnBeginDrag NOT , the same. Although they almost do the same, they were implemented to perform in different ways. Below I will describe most of them:

OnPointerDown : Called by pressing / touching the screen (when a button or finger is pressed on the touch screen)

OnPointerUp : Called when pressed / touched (when the click is released or the finger is removed from the touch screen)

OnBeginDrag : Called once before dragging (when moving the finger / mouse down for the first time)

OnDrag : Repeatedly called when the user drags the screen (when the finger / mouse moves around the touch screen)

OnEndDrag : Called when the drag stops (when the finger / mouse is no longer moving on the touch screen).

OnPointerDown compared to OnBeginDrag and OnEndDrag

OnPointerUp will be called NOT if OnPointerDown not . OnEndDrag will be called NOT if OnBeginDrag not . It's like braces in C ++, C #, you open it ' { ', and you close it> } ".

DIFFERENCE: OnPointerDown will be called once and immediately when the mouse pointer / mouse is displayed on the touch screen. Nothing else will happen until a mouse movement or finger movement appears on the screen, then OnBeginDrag will be called once , and then OnDrag.

They are designed for use in extended usage such as the custom user interface with controls that are not included in Unity.

WHEN USE EACH ONE:

1 .. When you need to perform a simple button , for example, the Up, Down, Shoot buttons on the screen, you only > need OnPointerDown to detect a touch. This should work for sprite images.

2 .. When you need to implement a custom switch and you want it to be realistic , so that the player can drag left / right or up / down to toggle , then you need OnPointerDown , OnBeginDrag , OnDrag , OnEndDrag , OnPointerUp . You need to write your code in this order so that a smooth transition appears on the screen. For some toggle switches, a click is used and it will switch . Some people prefer to do it realistically, making it so that you drag it to switch it.

3. Also, if you want to embed a popup that you can drag and drop, you also need to use these 5 functions ( OnPointerDown , OnBeginDrag , OnDrag , OnEndDrag , OnPointerUp ). First, when there is a click ( OnPointerDown ), make sure that the sprite click is the one you want to move. Wait for the player to move ( OnBeginDrag ) with your finger / mouse. As soon as they start dragging, perhaps you can call the coroutine function using the while loop , which starts moving Sprite inside this coroutine too, you can smoothly move Sprite with Time.deltaTime or in any other preferred way.

Since OnBeginDrag is called once, this is a good place to start a coroutine . When a player continues to drag Sprite, OnDrag will be called again . Use the OnDrag function to get the current location of the crawler and update it to Vector3 , which will be executed when the already accompanying version is executed > sprite position . When the player stops by moving the finger / mouse on the screen, OnEndDrag is OnEndDrag and you can boolean variable and tell the coroutine to stop the update , the Sprite position. Then, when the player releases his finger ( OnPointerUp ), you can stop the coroutine using the StopCoroutine function.

Due to OnBeginDrag we can start coroutine after the drag started, waiting for the drag to finish. start run , this will accompany in OnPointerDown , because it means that every time the player touches the screen, the coroutine will be launched .

Without OnBeginDrag we must use the boolean variable to force coroutine to run only once in the OnDrag function, which is called every time, or otherwise a coroutine will be executed, and the sprite will move unexpectedly.

4. If you want to determine how long the player has moved his finger. An example of this is the famous game called Fruit Ninja . Allows you to simply say that you want to determine how far the player has slipped on the screen.

Firstly, wait until OnPointerDown is called, wait until OnBeginDrag is called, then you can get the current position of the finger inside OnBeginDrag , because OnBeginDrag is called before the finger starts to move. After releasing the finger, OnEndDrag is OnEndDrag . Then you can again get the current position of the finger. You can use these two positions to check how far your finger is moved using subtraction .

If instead you decide to use OnPointerDown as a place to get the first position , you will get the wrong one because if the player moves to the right , then he waits and removes the left one , and then he waits and sweeps his finger up without releasing his finger after each , the only good result: the first miss (right napkin). The icon on the left and up will have invalid values, since this is the first value that you received when OnPointerDown was called this value, which you still use. This is due to the fact that the player never removed his finger from the screen, therefore , therefore , OnPointerDown never called again and the first old old meaning still exists.

But if you use OnBeginDrag instead of OnPointerDown , this problem will be gone , because when the finger stops moving , OnEndDrag is OnEndDrag and when it starts moving again OnBeginDrag is called again so that the first position is overwritten with a new one .

+16
source

The difference is that OnBeginDrag not called until the touch / mouse moves a certain minimum distance, the drag threshold. You can set the drag threshold for the Event System component.

This is necessary if you have a hierarchy of objects with various input processing methods, especially scrollviews. Imagine you have a scrollview with a vertical stack of cells, each with a button in it. When a touch first starts with one of the buttons, we don’t know if the user clicks the button or drags the scroll. Only when the touch reaches the drag threshold, we know that it is a drag, not a tap.

+1
source

Source: https://habr.com/ru/post/1243488/


All Articles