我不熟悉在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
答案 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;
}
}