物体拖拽效果OnDrag

[csharp]  view plain  copy
 print ?
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using UnityEngine.UI;  
  4. using UnityEngine.EventSystems;  
  5.   
  6. public class PetItemMove : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, ICanvasRaycastFilter  
  7. {  
  8.     private static Transform canvasTra;  
  9.     private Transform nowParent;//物品是格子的子物体,nowParent记录的是当前物品属于哪个格子(格子1)  
  10.     private bool isRaycastLocationValid = true;//默认射线不能穿透物品  
  11.     private Camera canvasCamera = null;  
  12.     void Start()  
  13.     {  
  14.   
  15.     }  
  16.   
  17.     public void OnBeginDrag(PointerEventData eventData)//开始拖拽  
  18.     {  
  19.         if (canvasTra == null) canvasTra = GameObject.Find("Canvas").transform;  
  20.         canvasCamera = canvasTra.GetComponentInChildren<Camera>();  //UICamera
  21.         //Debug.Log(Input.mousePosition);  
  22.         nowParent = transform.parent;//nowparent为被拖拽物体的原始父物体  
  23.         transform.SetParent(canvasTra);//将当前拖拽的物品放在canvas下  
  24.         isRaycastLocationValid = false;//ui穿透:置为可以穿透  【拖拽物体移动的时候鼠标下是有物体一直跟随遮挡的,如果不穿透就获取不到放置位置(OnEndDrag中判断是空格子,物体,还是无效位置)】  
  25.   
  26.     }  
  27.   
  28.     public void OnDrag(PointerEventData eventData)//拖拽过程中  
  29.     {  
  30.        transform.position = canvasCamera.ScreenToWorldPoint(Input.mousePosition);//鼠标左键按住拖拽的时候,物体跟着鼠标移动  
  31.         //transform.position = Input.mousePosition;//鼠标左键按住拖拽物体的时候不显示物体  
  32.   
  33.     }  
  34.   
  35.     public void OnEndDrag(PointerEventData eventData)//  
  36.     {  
  37.         GameObject go = eventData.pointerCurrentRaycast.gameObject;//获取到鼠标终点位置下 可能的物体  
  38.   
  39.           
  40.         if (go != null)  
  41.         {  
  42.             Debug.Log(go.name);  
  43.             if (go.tag.Equals("Grid"))//鼠标终点位置下是: 空格子(所以直接放进去)  
  44.             {  
  45.                 SetParentAndPosition(transform, go.transform);  
  46.             }  
  47.             else if (go.tag.Equals("PlayerPetItem"))//鼠标终点位置下是: 也是一个物体(所以需要交换位置)  
  48.             {//交换位置要注意可能需要把物品下的子物体的Raycast Target关掉(不去掉可能无法交换)  
  49.                 SetParentAndPosition(transform, go.transform.parent);//将被拖拽的物体1放到鼠标终点下的格子2里面  
  50.                 SetParentAndPosition(go.transform, nowParent);//将鼠标终点格子2里面物体2 放到 原来物体1的格子1里面  
  51.                 if (transform.position == go.transform.position)  
  52.                 {  
  53.                     Debug.Log("error");  
  54.                 }  
  55.             }  
  56.             else//鼠标终点是:无效位置(所以物体放回原来的位置)  
  57.             {  
  58.                 SetParentAndPosition(transform, nowParent);  
  59.             }  
  60.         }  
  61.         else//  
  62.         {  
  63.             SetParentAndPosition(transform, nowParent);  
  64.         }  
  65.         isRaycastLocationValid = true;//ui事件穿透:置为不能穿透  
  66.     }  
  67.   
  68.     private void SetParentAndPosition(Transform child, Transform parent)//将child放到parent下作为子物体  
  69.     {  
  70.         child.SetParent(parent);  
  71.         child.position = parent.position;  
  72.     }  
  73.   
  74.     public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)//UI事件穿透:如置为false即可以穿透,被图片覆盖的按钮可以被点击到  
  75.     {  
  76.         return isRaycastLocationValid;  
  77.     }  
  78. }  
 
### 如何在 Unity 中实现物体拖拽功能 在 Unity 中实现物体拖拽功能可以通过多种方式完成,具体取决于目标对象是 2D 还是 3D 对象以及是否涉及 UI 系统。以下是基于提供的引用内容和专业知识的详细说明。 #### 使用 UI 系统实现拖拽功能 当需要将 2D 物体作为 UI 元素(如 `Image` 或 `Button`)并利用 Unity 的 UI 系统进行拖拽时,可以遵循以下方法[^2]: - **命名空间引入** 需要导入特定的命名空间来支持事件处理机制: ```csharp using UnityEngine.EventSystems; ``` - **接口实现** 实现三个核心接口:`IBeginDragHandler`, `IDragHandler`, 和 `IEndDragHandler`。这些接口分别用于定义拖拽开始、正在进行和结束的行为。 ```csharp public class DragObject : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { public void OnBeginDrag(PointerEventData eventData) { // 拖拽开始逻辑 } public void OnDrag(PointerEventData eventData) { // 更新位置或其他状态 transform.position = Input.mousePosition; } public void OnEndDrag(PointerEventData eventData) { // 结束拖拽后的操作 } } ``` - **Canvas Group 组件的作用** 添加 `Canvas Group` 组件可以帮助检测被拖动物体下方的对象是否存在交互可能性。通过设置其属性 `.blocksRaycasts` 来控制光线投射行为[^1]: ```csharp CanvasGroup canvasGroup = GetComponent<CanvasGroup>(); canvasGroup.blocksRaycasts = false; // 关闭光线阻挡以便检测底层物体 ``` #### 协程与拖拽结合注意事项 如果计划使用协程移动物体,则需要注意继承上述提到的三个接口以确保正常工作。这是因为协程可能会影响事件系统的响应能力,从而导致无法正确识别底层物体的状态变化。 #### 扩展至三维环境中的拖拽 对于 3D 场景下的拖拽需求,通常会采用鼠标输入配合摄像机投影计算世界坐标的方式。这里提供一种常见做法,并借助 Quaternion.AngleAxis 方法调整方向角度[^3]: ```csharp public class Drag3DObject : MonoBehaviour { private Vector3 offset; private float distance; void OnMouseDown() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { distance = Vector3.Distance(hit.point, transform.position); // 记录初始距离 offset = transform.position - GetMouseAsWorldPosition(); } } void OnMouseDrag() { transform.position = GetMouseAsWorldPosition() + offset; // 可选旋转效果 float angle = Input.GetAxis("Mouse X") * 90f; // 假设每单位鼠标的横向位移对应90度角 transform.rotation *= Quaternion.AngleAxis(angle, Vector3.up); } Vector3 GetMouseAsWorldPosition() { Vector3 mousePoint = Input.mousePosition; mousePoint.z = distance; // 设置Z轴为之前记录的距离值 return Camera.main.ScreenToWorldPoint(mousePoint); } } ``` 此脚本实现了基本的 3D 拖拽功能,同时允许简单的旋转操作。 --- ### 总结 无论是针对 UI 元素还是 3D 游戏对象,在 Unity 中实现拖拽功能都依赖于合理运用事件系统或物理引擎特性。前者适合轻量级界面互动开发;后者则更贴近真实感模拟的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值