【发布时间】:2016-03-16 22:23:50
【问题描述】:
我担心单指移动代码中OnPointerDown 与OnBeginDrag 之间的区别。
(在使用物理光线投射器的最新 Unity 范例中:因此,最终,Unity 将正确忽略 UI 层上的触摸。
所以从 2015 年开始,你必须做的是:
-
忘掉传统的废话
Input或Touches系统,它们是毫无意义的废话并且不起作用 -
添加一个通常为 BoxCollider2D 的空游戏对象,可能比屏幕大。使图层称为“绘制”。物理设置,“画图”什么都没有交互
-
只需添加到相机中,2D 或 3D 物理射线投射器。事件遮罩“绘制”层。
像下面这样写一个脚本并把它穿上。
(提示 - 不要忘记在场景中简单地添加 EventSystem。奇怪的是,Unity 在某些情况下不会自动为您执行此操作,但 Unity 在其他情况下会自动为您执行此操作,所以如果你忘了!)
但是问题出在这里。
使用OnPointerDown 和OnBeginDrag(以及匹配的结束调用)之间肯定存在一些细微差别。 (您可以在以下代码示例中交换操作。)
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;
}
}
【问题讨论】:
-
公平地说,我之前没有使用过 OnPointerDown 和 OnBeginDrag,因为它在一两年前推出时出现了问题。我在移动设备上使用 raycast 来检测物体上的触摸。您想知道 OnPointerDown 和 OnBeginDrag 之间的区别以及何时应该使用它们吗?
-
我将您的脚本复制到了一个测试项目 Unity 5.2.1 中。当我单击 Box2D 时,它记录了 OnPointerDown 的东西,当我开始拖动它时,它记录了 OnBeginDrag 的东西。因此,如果您单击并按住但不移动,则调用 OnPointerDown,则不会调用 OnBeginDrag。
-
嗨,Prog & Nikster。是的,我理解其中的区别,正如 Nika 解释的那样……我想我想知道使用哪一个……事实上,在现实世界中,哪一个才是正确的选择?
-
@Programmer 我放了一个用于 3D 场景的超级方便的 pointerCurrentRaycast 示例。保存输入
标签: unity3d touch unity3d-ui