Unity全方位拖拽物体攻略

简介: Unity中UGUI控件和3D物体拖拽实现基本原理Unity拖拽的基本原理:射线检测,鼠标位置增量转换为统一空间的位置增量,将位置增量添加到拖拽物体原位置上。统一空间指的是将所有向量转换为同一空间下再进行计算。

Unity中UGUI控件和3D物体拖拽实现
基本原理
Unity拖拽的基本原理:射线检测,鼠标位置增量转换为统一空间的位置增量,将位置增量添加到拖拽物体原位置上。

统一空间指的是将所有向量转换为同一空间下再进行计算。

项目演示
左测:UGUI Button
中间:UGUI Image
右侧:3D物体

UGUI拖拽实现
方式有两种:其一直接继承拖拽三个接口IBeginDragHandler,IDragHandler,IEndDragHandler,重写内部函数。 其二通过EventSystem实现。

其一:脚本继承了拖拽三个接口IBeginDragHandler,IDragHandler,IEndDragHandler直接上代码,在开始拖拽的函数中初始化拖拽物和鼠标的位置,在拖拽过程中,不断的将鼠标的位置增量转换到画布空间,并附加给拖拽物。代码如下(项目演示中中间image是用此种方法拖拽):

public class DragTest : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler
{
private Vector3 pos; //控件初始位置
private Vector2 mousePos; //鼠标初始位置(画布空间)
private Vector3 mouseWorldPos; //鼠标初始位置(世界空间)
private RectTransform canvasRec; //控件所在画布
private void Start()
{
canvasRec = this.GetComponentInParent().transform as RectTransform;
}
//开始拖拽
public void OnBeginDrag(PointerEventData eventData)
{
//控件所在画布空间的初始位置
pos = this.GetComponent().anchoredPosition;
Camera camera = eventData.pressEventCamera;
//将屏幕空间鼠标位置eventData.position转换为鼠标在画布空间的鼠标位置
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRec, eventData.position, camera, out mousePos);
}
//拖拽过程中
public void OnDrag(PointerEventData eventData)
{
Vector2 newVec = new Vector2();
Camera camera = eventData.pressEventCamera;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRec, eventData.position, camera, out newVec);
//鼠标移动在画布空间的位置增量
Vector3 offset = new Vector3(newVec.x - mousePos.x, newVec.y - mousePos.y, 0);
//原始位置增加位置增量即为现在位置
(this.transform as RectTransform).anchoredPosition = pos + offset;

}
//结束拖拽(此处没做任何处理,可自行拓展)
public void OnEndDrag(PointerEventData eventData)
{
}
}
当然也可以转换到世界空间进行计算,相关代码如下:

//开始拖拽函数
//控件的世界坐标初始位置
pos = this.transform.position;
Camera camera = eventData.pressEventCamera;
//将屏幕空间鼠标位置eventData.position转换为鼠标在世界空间的鼠标位置
RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRec, eventData.position, camera, out mouseWorldPos);

//拖拽中函数
Vector3 newVec = new Vector3();
Camera camera = eventData.pressEventCamera;
RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRec, eventData.position, camera, out newVec);
//鼠标移动在世界空间的位置增量
Vector3 offset = newVec - mouseWorldPos;
//原始位置增加位置增量即为现在位置
this.transform.position = pos + offset;
其二通过EventSystem实现:控件添加EventTrigger组件,在代码中EventTrigger添加EventTriggerType.BeginDrag,EventTriggerType.Drag,EventTriggerType.EndDrag事件,并给各事件绑定函数,左侧的button就是用这种方式实现的,代码如下(其实核心模块的逻辑与上面方法无异):

public class EventSystemDrag : MonoBehaviour {

public Camera theCamera; //UI摄像机
public RectTransform canvas; //控件所在画布
private EventTrigger trigger; //事件触发组件

Vector3 mouseOriPos; //鼠标原始位置(世界空间)
Vector3 myOriPos; //控件原始位置(世界空间)

// Use this for initialization
void Start () {
trigger = this.GetComponent();

//事件触发器添加开始拖拽事件并添加开始拖拽函数
EventTrigger.Entry entry2 = new EventTrigger.Entry();
entry2.eventID = EventTriggerType.BeginDrag;
entry2.callback = new EventTrigger.TriggerEvent();
entry2.callback.AddListener((eventData) => { BeginDrag(eventData as PointerEventData); });
trigger.triggers.Add(entry2);

//事件触发器添加拖拽事件并添加拖拽函数
EventTrigger.Entry entry3 = new EventTrigger.Entry();
entry3.eventID = EventTriggerType.Drag;
entry3.callback = new EventTrigger.TriggerEvent();
entry3.callback.AddListener((eventData) => { OnDrag(eventData as PointerEventData); });
trigger.triggers.Add(entry3);

//事件触发器添加拖拽结束事件并添加拖拽结束函数
EventTrigger.Entry entry4 = new EventTrigger.Entry();
entry4.eventID = EventTriggerType.EndDrag;
entry4.callback = new EventTrigger.TriggerEvent();
entry4.callback.AddListener((eventData) => { EndDrag(eventData as PointerEventData); });
trigger.triggers.Add(entry4);

}

public void BeginDrag(PointerEventData eventData)
{
Vector2 vec = eventData.position;
RectTransformUtility.ScreenPointToWorldPointInRectangle(canvas, vec, theCamera,out mouseOriPos);
myOriPos = this.transform.position;
}

void OnDrag(PointerEventData eventData)
{
Vector2 vec = eventData.position;
Vector3 newVec = new Vector3();
RectTransformUtility.ScreenPointToWorldPointInRectangle(canvas, vec, theCamera, out newVec);
this.transform.position = myOriPos + newVec - mouseOriPos;
}

void EndDrag(PointerEventData eventData)
{

}
}
或者可以直接在Unity编辑器中添加事件和绑定函数,效果是一样的,如图:

111.png

3D物体拖拽
由于UI拖拽,关于射线部分,Unity底层已经封装好了接口,我们只用实现响应的接口即可。但是3D物体,需要我们自己写代码实现。
项目演示中右侧小球的部分属性如下图(设置了Tag,方便射线检测,小球必须添加碰撞体组件,否则射线无法检测到):

qiu.png

首先我们实现射线检测部分,代码如下:

//按下左键开始发出射线
if (Input.GetMouseButtonDown(0))
{
//射线由主摄像机发出,射向屏幕点击的点
Ray ray = theCamera.ScreenPointToRay(Input.mousePosition);
//射线撞击点
RaycastHit hit;
//如果射线撞击到碰撞体,且碰撞体的标签是我们设置需要拖拽的物体,那么进行主逻辑
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.tag == "Drag")
{
//记录下当前鼠标位置
mousePos = Input.mousePosition;
isDrag = true;
go = hit.collider.gameObject;
//记录下拖拽物的原始屏幕空间位置
oriScreenPos = theCamera.WorldToScreenPoint(go.transform.position);
}
}
}
接着是移动的逻辑:

//左键一直处于按下状态,即为拖拽过程
if (Input.GetMouseButton(0))
{
//如果拖拽状态处于true,且有拖拽物
if (isDrag&& go)
{
//获取屏幕空间鼠标增量,并加上拖拽物原始位置(屏幕空间计算)
Vector3 newPos = oriScreenPos + Input.mousePosition - mousePos;
//将屏幕空间坐标转换为世界空间
Vector3 newWorldPos = theCamera.ScreenToWorldPoint(newPos);
//将世界空间位置赋予拖拽物
go.transform.position = newWorldPos;
}
}
移动结束,还原拖拽状态:

//松开左键
if (Input.GetMouseButtonUp(0))
{
isDrag = false;
go = null;
}
本文使用的屏幕空间计算,当然使用其他空间也是可以的,比如世界空间,但要注意坐标Z轴的处理。原因如下:世界空间坐标是三维向量(世界空间),而鼠标点击屏幕的坐标(屏幕空间),其实为二维向量,z方向为0值。那么拖拽中实际上拖拽物只有x,y值具有增量,而z值不变。或者开发者也可以根据自己的需求来修改z值。

更多unity2018的功能介绍请到paws3d爪爪学院查找。

相关文章
|
图形学
Unity UGUI拖拽移动
本文介绍了两种UI拖拽实现方式:精准拖拽和克隆拖拽。精准拖拽通过计算鼠标点击点与UI中心的偏移量,使UI跟随鼠标移动,适用于需要精确控制的场景。代码中通过`IBeginDragHandler`、`IDragHandler`和`IEndDragHandler`接口实现拖拽逻辑。克隆拖拽则在拖拽时克隆一个UI对象,使其跟随鼠标移动,适合视觉效果需求较高的场景。代码中同样使用上述接口,并在拖拽结束时销毁克隆对象。具体实现可参考提供的代码示例。
614 10
|
图形学
Unity 获取鼠标位置下的UGUI或3D物体
本文总结了两种检测方法,分别用于UGUI和3D物体的检测。第一种方法`GetOverUIobj`专门用于检测鼠标悬停的UGUI元素,通过`GraphicRaycaster`实现。第二种方法`GetOverWordGameObject`则同时适用于UI和3D物体检测,利用`PhysicsRaycaster`进行射线检测。两者均返回悬停对象或null。
|
图形学
unity 物体震动
在Unity中实现物体震动效果,主要通过改变物体的位置、旋转或缩放属性来模拟震动。以下是位置震动的实现原理及代码示例:通过随机生成微小偏移量并累加到物体位置上,在短时间内不断改变位置产生震动效果。生成随机偏移,并结合时间控制持续震动。
|
前端开发 图形学
unity UGUI跟随3D物体的坐标转换
在 Unity 中实现 UGUI 元素跟随 3D 物体,关键是将 3D 物体的世界坐标转换为屏幕或画布坐标。通过 Camera.WorldToScreenPoint 方法,可将 3D 物体位置映射到屏幕上,再更新 UGUI 元素的位置。代码示例展示了如何使用该方法,使 UGUI 图像跟随 3D 模型,并提供文字显示、图像和线条的显示/隐藏功能。
|
存储 图形学 索引
unity 使物体跟随路径点自动移动位置
在Unity中,物体沿路径点自动移动的核心原理是通过预设路径点,控制物体依次移动。路径点可用空对象或三维向量数组定义,并按顺序存储。移动时,计算当前位置与下一个路径点的向量差以确定方向,使用`Vector3.MoveTowards`逐步靠近目标点。代码实现包括路径点设置、移动控制及插值计算,确保物体平滑移动和旋转。
|
图形学
Unity 射线移动物体Ray
在Unity中,通过射线检测实现3D物体的拖拽和移动。射线由起点和方向组成,使用`Physics.Raycast`检测与物体的交点。点击物体时,记录位置偏移量,拖动过程中更新物体位置。代码包括基本拖拽和上下拖动功能,适用于正交摄像机场景。测试时为物体设置特定标签(如"JQR")以便区分和操作。 示例代码展示了如何通过鼠标事件控制物体移动,并结合层级掩码优化射线检测。具体实现包括:点击选中物体、拖动更新位置、释放鼠标取消选择。此外,提供了上下拖动的额外功能,通过按键切换模式。
|
图形学 开发者
unity 从工具栏拖动生成物体
在 Unity 中实现从工具栏拖动生成物体的功能,基于编辑器扩展、事件系统和预制体实例化。通过自定义编辑器窗口、处理鼠标事件(按下、移动、释放)及使用 Instantiate 方法,可实现拖动并生成预制体物体。代码示例展示了如何检测鼠标事件并在指定位置实例化物体。
|
前端开发 图形学
Unity精华☀️UI和物体可见性的判断方法
Unity精华☀️UI和物体可见性的判断方法
小功能⭐️获取Unity游戏物体上,所挂载组件的名称
小功能⭐️获取Unity游戏物体上,所挂载组件的名称

热门文章

最新文章

下一篇
开通oss服务