unity3d - Unity3D中OnPointerDown与OnBeginDrag的恐怖

标签 unity3d touch unity3d-ui

我担心单指运动代码中OnPointerDownOnBeginDrag之间的区别。
(在最新的使用物理光线投射器的Unity范例中:因此,最终,Unity将正确忽略UI层上的触摸。
因此,从2015年开始,您必须做的是:

  • 忘了废话传统的InputTouches系统,它们是毫无意义的废话,不起作用
  • 添加一个通常为BoxCollider2D的空游戏对象,该对象可能大于屏幕。使称为“绘图”的图层。物理设置,“绘图”没有任何作用
  • 只需将2D或3D物理光线投射器添加到相机中即可。事件遮罩“绘图”层。

  • enter image description here
    像下面这样编写脚本并放上它。
    (提示-不要忘记简单地在场景中添加一个EventSystem。奇怪的是,Unity在某些情况下不会自动为您执行此操作,但在其他情况下Unity会自动为您执行此操作,因此,如果您忘记了,那会很烦人!)
    但是这是问题
    在使用OnPointerDownOnBeginDrag(以及匹配的结束调用)之间必须有一些细微的区别。 (您可以只交换以下代码示例中的操作。)
    自然,Unity在这方面不提供任何指导。以下代码精美地拒绝了流浪者,并且完美地忽略了您的UI层(感谢Unity!最后!),但是我对这两种方法之间的区别(开始拖动V.开始触摸)感到迷惑不解,无论如何我都找不到逻辑上的区别在单元测试中两者之间。
    答案是什么?
    /*
    
    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);
        }
      }
    
    这是一件方便的事情。使用鲜为人知但精致的3D场景,用相同的内容保存键入内容
    pointerCurrentRaycast
    这是...如何注意到优秀
    data.pointerCurrentRaycast.worldPosition
    
    致电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;
        }
      }
    

    最佳答案

    我首先要说InputTouches并不糟糕,它们仍然有用,并且是在touchOnPointerDown出现之前在移动设备上检查OnBeginDrag的最佳方法。您可以将OnMouseDown()称为crappy,因为它并未针对移动设备进行优化。对于刚开始学习Unity的初学者,他们可以选择InputTouches
    至于您的问题,OnPointerDownOnBeginDrag,而不是。尽管它们几乎做相同的事情,但是它们被实现为以不同的方式执行。下面我将描述其中的大多数:OnPointerDown:
    当屏幕上有按下/触摸时(在触摸屏上单击或按下手指时)调用OnPointerUp:
    释放按下/触摸(释放点击或从触摸屏上移开手指)时调用OnBeginDrag:
    在开始拖动之前,将其称为一次(当手指/鼠标向下移动的第一个时间时)OnDrag:
    当用户在屏幕上拖动时(当手指/鼠标在触摸屏上移动时)反复调用OnEndDrag:
    当拖动停止时调用(当手指/鼠标不再在触摸屏上移动时,不再调用时调用)。
    OnPointerDown OnBeginDrag OnEndDrag
    如果尚未调用OnPointerUp ,则将调用,而不调用。如果尚未调用OnPointerDown ,则将调用,而不调用。就像C++,C#中的花括号一样,您打开,将其' {',然后关闭,将其'} '。
    差异:
    当手指/鼠标在触摸屏上时,OnPointerDown将被称为
    ,一旦被命名为
    ,则立即被称为
    。除非有鼠标移动或手指在屏幕上移动,否则什么都不会发生,一旦
    后跟OnDrag,则OnEndDrag将称为
    这些是为进行高级使用而设计的,例如带有未包含在Unity中的控件的自定义 UI。
    每次使用时:
    1. 当您必须执行简单单击按钮时(例如,屏幕上的向上,向下,拍摄按钮),您需要OnBeginDrag来检测触摸。这应该适用于Sprite图片。
    2. 如果您必须实现自定义切换开关,并且希望它是现实的,以便玩家可以向左/向右或向上/向下拖动到切换,则需要OnBeginDragOnPointerDownOnPointerDownOnBeginDragOnDrag。您需要以此顺序编写代码,以在屏幕上显示平滑 Sprite / Texture过渡。一些切换开关被设置为单击,它将切换。某些人喜欢通过使其变得逼真来使它看起来逼真,因此您必须拖动以便将切换到
    3. 同样,当您要实现可拖拽的通用可重用弹出窗口 时,还需要使用这5个函数(OnEndDragOnPointerUpOnPointerDownOnBeginDragOnDrag)。
    首先检测是否有一个click(OnEndDrag),检查以确保单击的Sprite是您要移动的正确的Sprite。等待玩家移动(OnPointerUp)他们的手指/鼠标。一旦他们开始拖动,也许您可​​以使用OnPointerDown调用协程函数循环,它将开始移动Sprite,并在该协程内部,您可以使用OnBeginDrag或其他任何首选方法平滑 Sprite的运动。
    由于while曾经被调用过,因此它是开始协程的好地方。
    当玩家继续拖动Sprite时,Time.deltaTime将重复称为 。使用OnBeginDrag函数获取查找器的当前位置,并将其更新为OnDrag,已运行
    的协程的协程将用于更新,将Sprite的位置更新。当播放器停止在屏幕上移动手指/鼠标的时,会调用OnDrag,您可以Vector3变量并告诉协程停止更新的Sprite位置。然后,当玩家释放手指(OnEndDrag)时,您可以使用StopCoroutine函数停止协程。
    由于有了boolean,我们可以在拖动开始后就开始协程,而等待拖动结束。 不会使成为,以来启动OnPointerUp中的协程,因为这意味着每次玩家触摸屏幕时,协程将是来启动
    没有OnBeginDrag,我们必须使用OnPointerDown变量使协程仅在每次调用的OnBeginDrag函数中启动一次,否则协程将在各处运行,并且Sprite会发生意外移动。
    4. 当您想确定玩家移动手指多长时间时。例如,著名游戏水果忍者。假设您要确定玩家在屏幕上滑动的距离。
    首先,等待直到调用boolean再次等待直到调用OnDrag,然后您可以获取OnPointerDown函数内手指的当前位置,因为在手指开始移动之前调用了OnBeginDrag。释放手指后,将调用OnBeginDrag。然后,您可以再次获取手指的当前位置。您可以使用这两个
    位置
    来检查减去后手指移动了多远。
    如果您决定使用OnBeginDrag作为获取手指的第一个 位置的位置,则会得到错误的结果,因为如果播放器向右滑动,则会向左滑动 再次等待,然后向上滑动 ,而在每次滑动之后不松开手指,唯一的良好结果是第一次滑动(正确的swipe)。左侧
    上的和向上滑动将具有无效的值,因为在OnEndDrag时获得的第一个值称为,是您仍在上使用的值。这是因为玩家从未将手指从屏幕上移开,因此因此OnPointerDown不再是,从再也称为,不再是
    ,并且第一个旧旧值仍然存在。
    但是,当您使用OnPointerDown而不是OnPointerDown时,此问题将变成消失了,因为当手指停止移动时,将调用OnBeginDrag,并在其再次开始移动时再次调用OnPointerDown,从而导致第一个位置覆盖使用新的

    关于unity3d - Unity3D中OnPointerDown与OnBeginDrag的恐怖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36048106/

    相关文章:

    c# - 实例化的预制比例在客户端上显示不正确

    c# - Unity C# 中嵌套字典的奇怪行为

    linux - bash/linux - touch/mkdir 来自文件中的字符串

    ios - 有没有办法以位图形式获取 iPad/iPhone 的当前 'touch pattern'?

    unity3d - 从内容中删除/停用子元素后,ScrollRect 在固定规范化位置时无法正确更新位置

    c# - 如何从 Unity 连接到数据库

    java - 如何在android触摸监听器中检测不同时间触摸屏幕的辅助手指?

    unity3d - 如何在 RectTransform 中计算 sizeDelta?

    ios - Unity3d 编辑器和 iPhone6 设备上的 Sha1 hash 不同