Unity3D OnDrag移动3D对象不跟随指针

时间:2017-01-13 13:10:34

标签: c# unity3d 3d

我不熟悉在3D世界中将屏幕坐标转换为世界坐标的概念,在Unity中更是如此。我正在使用UnityEngine.EventSystems库,实现IDragHandler,因为无论鼠标或触摸输入是否来源,我希望它的工作方式相同。

我想在世界空间中拖动一个3D对象,锁定到一个z位置。我找到了这个我正在使用的优秀代码: http://coffeebreakcodes.com/drag-object-with-mouse-unity3d/

同样的代码也可以在答案中找到:Drag 3d object using fingers in unity3d

它完全按照我想要的方式工作,除了一件事:当拖动开始时转换工作正常,但是对象比指针做更大的移动,从对象的原始位置越远越好,如果运动乘以越大的东西越远离我得到的原始位置。

这是我的代码,除了使用PointerEventData的指针坐标而不是Input.mousePosition(一个不影响行为的更改)之外,它与上面的链接基本相同:

public class DragInput : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    private Vector3 screenPoint;
    private Vector3 offset;

    public void OnBeginDrag(PointerEventData eventData)
    {
        screenPoint = Camera.main.WorldToScreenPoint(transform.position);
        offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(eventData.position.x, eventData.position.y, screenPoint.z));
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector3 cursorPoint = new Vector3(eventData.position.x, eventData.position.y, screenPoint.z);
        Vector3 cursorPosition = Camera.main.ScreenToWorldPoint(cursorPoint) + offset;
        transform.position = cursorPosition;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
    }
}

编辑:此视频剪辑展示了我所描述的行为:https://www.dropbox.com/s/qfx2p6kznizft1q/Unity%202017-01-13%2014-32-15-89.avi?dl=0

3 个答案:

答案 0 :(得分:1)

这是在3D对象周围拖动时的透视问题。

你需要制作一个Plane,将鼠标位置(屏幕像素)转换为光线,然后检查它们相交的位置。

using UnityEngine;
using UnityEngine.EventSystems;

public class DragInput : MonoBehaviour, IPointerDownHandler, IDragHandler, IEndDragHandler
{
    Camera mainCamera;
    float zAxis = 0;
    Vector3 clickOffset = Vector3.zero;

    // Use this for initialization
    void Start()
    {
        mainCamera = Camera.main;
        zAxis = transform.position.z;
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        clickOffset = transform.position - mainCamera.ScreenPointToWoldOnPlane(eventData.position, zAxis);
    }

    public void OnDrag(PointerEventData eventData)
    {
        transform.position = mainCamera.ScreenPointToWoldOnPlane(eventData.position, zAxis) + clickOffset;
    }

    public void OnEndDrag(PointerEventData eventData)
    {

    }
}

public static class extensionMethod
{
    public static Vector3 ScreenPointToWoldOnPlane(this Camera cam, Vector3 screenPosition, float zPos)
    {
        float enterDist;
        Plane plane = new Plane(Vector3.forward, new Vector3(0, 0, zPos));
        Ray rayCast = cam.ScreenPointToRay(screenPosition);
        plane.Raycast(rayCast, out enterDist);
        return rayCast.GetPoint(enterDist);
    }
}

答案 1 :(得分:0)

我发布的问题的原因是由于我忘记了MainCamera上的PhysicsRaycaster。我在Canvas上有一个GraphicsRaycaster,但没有PhysicsRaycaster存在 - 我认为这可能会导致奇怪的行为。

但是,我的代码与我描述的其他所需行为有问题,将对象移动到相机的固定距离。请参阅@ Programmer的答案,了解如何解决这个问题。

然而,他们的代码并不能解决这篇文章的目的,因此他们的答案不是公认的答案。

答案 2 :(得分:-1)

看一下这个片段:

pos = Camera.main.ScreenToWorldPoint (Vector3 (Input.GetTouch(0).position.x,Input.GetTouch(0).position.y, 5));
transform.position = new Vector3(pos.x, pos.y, pos.z);

或者你可以尝试这个课程,如果这不起作用,我就没有选择了:)

using UnityEngine;
using System.Collections;

public class DragObject : MonoBehaviour {

 private float dist;
 private Vector3 v3Offset;
 private Plane plane;
 private bool ObjectMouseDown = false;
 public GameObject linkedObject;

 void OnMouseDown() {
     plane.SetNormalAndPosition(Camera.main.transform.forward, transform.position);
     Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
     float dist;
     plane.Raycast (ray, out dist);
     v3Offset = transform.position - ray.GetPoint (dist);     
     ObjectMouseDown = true;
 }

 void OnMouseDrag() {
     if (ObjectMouseDown == true){
         Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
         float dist;
         plane.Raycast (ray, out dist);
         Vector3 v3Pos = ray.GetPoint (dist);
         v3Pos.z = gameObject.transform.position.z;
         v3Offset.z = 0;
         transform.position = v3Pos + v3Offset;

         if (linkedObject != null){ 
             linkedObject.transform.position = v3Pos + v3Offset;
         }
     }
 }

 void OnMouseOut() {
     ObjectMouseDown = false;
 }

 }