unity 实现接口,3d物体拖拽

using UnityEngine.EventSystems;
using System;
using MessageBoxNS;
using UnityEngine;
using TMPro;
using GunAssembly.Facade;

namespace GunAssembly.View
{
    public class GunUIPartItem : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler,
IInitializePotentialDragHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
    {
        /// <summary>
        /// 是否正在拖拽中
        /// </summary>
        public static bool IsDrag = false;

        /// <summary>
        /// Q的名字
        /// </summary>
        public string GunName;

        /// <summary>
        /// 零件名称
        /// </summary>
        public TextMeshProUGUI TextMesh;

        /// <summary>
        /// 零件的说明
        /// </summary>
        public string PartExplain;

        /// <summary>
        /// 零件名称
        /// </summary>
        public string PartName
        {
            get
            {
                return TextMesh.text;
            }
            set
            {
                TextMesh.text = value;
            }
        }

        /// <summary>
        /// 设置该零件是否已经完成
        /// </summary>
        public bool IsCurrentPartFinish;

        /// <summary>
        /// 当前零件所属的步骤
        /// </summary>
        public int CurrentPartStep;

        public GunUIView View;

        /// <summary>
        /// 当前零件的目标对象
        /// </summary>
        private GameObject TargetObj;

        /// <summary>
        /// 拖拽对象
        /// </summary>
        private GameObject ResouceObj;


        public void OnPointerEnter(PointerEventData eventData)
        {
            if (!IsDrag)
            {
                View.SetGunPartInfo(PartExplain);
            }
        }

        public void OnPointerExit(PointerEventData eventData)
        {
            if (!IsDrag)
            {
                View.SetGunPartInfo("");
            }
        }

        public void OnInitializePotentialDrag(PointerEventData eventData)
        {
            View.SetGunPartInfo(PartExplain);
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            IsDrag = true;
            CameraObserve.Instance.CanMove = false;
            ResouceObj = CreatDragObj(PartName);
        }

        public void OnDrag(PointerEventData eventData)
        {
            if (IsDrag)
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit))
                {
                    GameObject gameObj = hit.collider.gameObject;
                    if (gameObj.name.Equals(PartName) && !IsCurrentPartFinish)
                    {
                        IsCurrentPartFinish = true;
                        OnEndDrag(null);
                        AppFacade.Instance.SendNotification(Events.Events.UpdateView, this);
                    }
                }
            }
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            IsDrag = false;
            CameraObserve.Instance.CanMove = true;
            if (ResouceObj != null) Destroy(ResouceObj);
            View.SetGunPartInfo("");
        }



        /// <summary>
        /// 生成预制
        /// </summary>
        /// <param name="partName"></param>
        private GameObject CreatDragObj(string partName)
        {
            GunModelViewMediator gunModelViewMediator = Facade.AppFacade.Instance.RetrieveMediator(GunModelViewMediator.NAME) as GunModelViewMediator;
            TargetObj = gunModelViewMediator.GetGunPart(PartName);
            return Instantiate(Resources.Load("Model/Part/" + GunName + "/" + PartName) as GameObject);
        }

        private void Update()
        {
            if (IsDrag && ResouceObj != null)
            {
                float distance = Vector3.Distance(Camera.main.transform.position, TargetObj.transform.position);
                Vector3 Pos = Camera.main.ScreenToWorldPoint(Input.mousePosition + new Vector3(0, 0, distance));
                ResouceObj.transform.position = Pos;
            }
        }
    }
}

主要逻辑还是在OnDrag里边

### 实现3D物体拖动功能 为了实现Unity中通过脚本实现3D物体的拖动功能,可以采用两种主要方法:一种是基于物理系统的碰撞检测机制[^1];另一种则是利用UGUI事件系统并结合自定义脚本来处理不同阶段的操作[^2]。 #### 方法一:基于物理系统的拖拽方式 当希望在移动设备上轻松地对任何具有碰撞器组件的对象执行拖拽操作而不必为每一个对象单独编写逻辑时,此方案尤为适用。具体来说,在检测到用户触碰到了某个带有碰撞器的游戏对象之后,程序会记录下这个交互行为,并随着用户的指尖移动相应调整目标的位置直到接触结束为止。 ```csharp using UnityEngine; public class DragObject : MonoBehaviour { private Rigidbody rb; private Vector3 offset; void OnMouseDown() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; if (Physics.Raycast(ray, out hitInfo)) { transform.position = hitInfo.point; // 将点击位置设置为目标初始位置 rb = GetComponent<Rigidbody>(); if (!rb) rb = gameObject.AddComponent<Rigidbody>(); // 如果不存在刚体,则添加之 rb.isKinematic = true; // 设置为运动学模式以便手动控制其位移变化 offset = transform.position - new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z); } } void OnMouseDrag() { Vector3 curScreenPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z); Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPos + offset); transform.position = curPosition; } void OnMouseUp() { if (rb != null) rb.isKinematic = false; // 结束拖拽后恢复默认状态 } } ``` 这段代码展示了如何监听鼠标的按下、拖动以及释放事件来改变被选中的游戏对象的位置。这里的关键在于`OnMouseDown()`函数用于初始化过程,计算出偏移量以保持鼠标指针相对于所选对象的一致性;而在`OnMouseDrag()`里则不断更新坐标使得跟随手势动作平滑过渡;最后由`OnMouseUp()`负责清理工作,比如重置刚体属性等。 #### 方法二:使用UGUI事件处理器的方式 对于更复杂的界面设计或是想要更好地集成进现有项目结构的情况下,推荐第二种做法——即借助于Unity GUI(简称UGUI)框架下的几个重要接口完成相同目的的任务。这主要包括实现了三个特定接口(`IDragHandler`, `IBeginDragHandler`, 和 `IEndDragHandler`) 的类文件,它们各自关联着不同的生命周期节点从而允许开发者精确掌控整个流程。 ```csharp using UnityEngine.EventSystems; public class UGUISimpleDraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { public Transform parentToReturnTo = null; private Transform originalParent = null; public void OnBeginDrag(PointerEventData eventData) { originalParent = transform.parent; transform.SetParent(parentToReturnTo); } public void OnDrag(PointerEventData eventData) { transform.position = eventData.position; } public void OnEndDrag(PointerEventData eventData) { transform.SetParent(originalParent); } } ``` 上述示例说明了一个简单的可拖拽项应该怎样响应来自屏幕输入的各种信号。值得注意的是,这种方法更适合那些已经构建好较为完善的视觉效果并且期望获得更加直观用户体验的应用场景之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值