一、拖拽overlay模式的Canvas下的ui元素
这种情形比较简单,直接上代码,代码挂在UI元素上即可。
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System;
public class UIDrag : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler
{
void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
{
print("start drag");
print(Input.mousePosition);
}
void IDragHandler.OnDrag(PointerEventData eventData)
{
transform.position = eventData.position;//eventData就是屏幕坐标下的鼠标位置
}
void IEndDragHandler.OnEndDrag(PointerEventData eventData)
{
print("end drag");
}
}
继承以上接口实现方法即可。
二、拖拽世界坐标下的UI元素
因为是在世界坐标下的canvas,直接赋值会导致UI不在canvas平面下平移,所以需要进行坐标转换,代码如下,代码挂在UI元素上即可。
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System;
public class UIWorldDrag : MonoBehaviour,IDragHandler {
public Vector3 pos = new Vector2();
void IDragHandler.OnDrag(PointerEventData eventData)
{
RectTransformUtility.ScreenPointToWorldPointInRectangle(GetComponent<RectTransform>(), eventData.position,
Camera.main, out pos);
transform.position=pos;
}
}
三、拖拽3D物体在平面上移动
首先要想点击3D物体,需要在主相机上挂载Physicsraycaster组件,实现思路,使用射线检测得到从屏幕位置到目标平面的点,将点的坐标赋给3D物体即可。代码如下,挂在3D物体上即可。
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System;
public class WorldDrag : MonoBehaviour ,IDragHandler{
public Vector3 hitPos;
public void OnDrag(PointerEventData eventData)
{
Vector3 sc = new Vector3(eventData.position.x, eventData.position.y, 10);
Ray ray = Camera.main.ScreenPointToRay(sc);
Debug.DrawRay(Camera.main.transform.position, ray.direction, Color.blue);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 20, LayerMask.GetMask("Plane")))
{
hitPos = hit.point;
}
transform.position = hitPos;
}
}
为了让射线只与目标平面碰撞,需要给平面添加自定义的layer,射线检测时只与layer检测。
补充:
考虑到使用物体射线浪费性能,在查阅了RectTransformUtility.ScreenPointToWorldPointInRectangle()方法的源码后,对以上代码做出修改如下:
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System;
public class WorldDrag : MonoBehaviour ,IDragHandler{
public Vector3 hitPos;
public Transform planTransform;
public void OnDrag(PointerEventData eventData)
{
Vector3 sc = new Vector3(eventData.position.x, eventData.position.y, 10);
Ray ray = Camera.main.ScreenPointToRay(sc);
Debug.DrawRay(Camera.main.transform.position, ray.direction, Color.blue);
float num;
Plane plane = new Plane(planTransform.rotation*Vector3.up, planTransform.position);
if (plane.Raycast(ray, out num))
{
hitPos = ray.GetPoint(num);
}
//RaycastHit hit;
//if (Physics.Raycast(ray, out hit, 20, LayerMask.GetMask("Plane")))
//{
// hitPos = hit.point;
//}
transform.position = hitPos;
}
}
使用plane来模拟目标平面,同理射线检测得到交点位置。
RectTransformUtility.ScreenPointToWorldPointInRectangle()方法的源码如下:
public static bool ScreenPointToWorldPointInRectangle(RectTransform rect, Vector2 screenPoint, Camera cam, out Vector3 worldPoint)
{
float num;
worldPoint = (Vector3) Vector2.zero;
Ray ray = ScreenPointToRay(cam, screenPoint);
Plane plane = new Plane((Vector3) (rect.rotation * Vector3.back), rect.position);
if (!plane.Raycast(ray, out num))
{
return false;
}
worldPoint = ray.GetPoint(num);
return true;
}