使用OnMouseDrag拖拽物体到指定位置

实现拖拽物体到指定线框位置的效果

为了更明显展示用了发光插件Highlight Plus和线框材质,编辑器里除了要进行移动的物体外,目标位置都是用Cube。

挂载组件:

移动的物体:碰撞体(需要勾选触发器),刚体,发光组件(不激活)

目标物体:碰撞体,发光组件(目标物体组件全部不激活)

新建一个脚本用于控制物体拖拽,代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HighlightPlus;

public class OnDragObj : MonoBehaviour
{
    public GameObject targeObj;//目标物体位置(初始隐藏)
    bool allowDrag, isCollision;//是否允许拖拽,是否发生碰撞
    public bool isArriveTarge;//是否到达目标位置
    float h;//初始高度
    float z;//初始深度
    public void Start()
    {
        allowDrag = true;
        IsEnableComponent<HighlightEffect>(transform, true);
        h = transform.position.y;
        z = transform.position.z;
    }
    private void OnMouseDrag()
    {
        if (allowDrag)
        {
            //如果开始拖拽,显示目标物体并激活其碰撞体组件和发光组件
            targeObj.SetActive(true);
            IsEnableBoxCollider(targeObj.transform,true);
            IsEnableComponent<HighlightEffect>(targeObj.transform, true);
            //存放鼠标位置
            Vector3 mousePos = Input.mousePosition;
            //将当前物体位置转换为屏幕坐标并赋值给鼠标位置,保证物体深度不会发生变化
            mousePos.z = Camera.main.WorldToScreenPoint(transform.position).z;
            //将鼠标位置转化为世界坐标
            Vector3 objectPos = Camera.main.ScreenToWorldPoint(mousePos);
            //限制该世界坐标高度不能小于初始高度
            if (objectPos.y <= h)
            {
                objectPos.y = h;
            }
            //限制该世界坐标深度为物体初始深度
            objectPos.z = z;
            //给物体赋值坐标
            transform.position = objectPos;
        }
    }
    private void OnMouseUp()
    {
        //当鼠标抬起时,关闭目标物体的发光体组件
        IsEnableComponent<HighlightEffect>(targeObj.transform, false);
        if (isCollision)
        {
            //如果发生了碰撞不再允许拖拽,且让物体直接吸附到目标位置去,并关闭发光组件,目标物体消失,传出到达目标位置信息
            allowDrag = false;
            transform.position = targeObj.transform.position;
            IsEnableComponent<HighlightEffect>(transform, false);
            targeObj.SetActive(false);
            isArriveTarge = true;
        }
    }
    /// <summary>
    /// 当触发器触发了,如果触发的碰撞体是目标物体就传出发生碰撞
    /// </summary>
    /// <param name="other"></param>
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject == targeObj)
            isCollision = true;
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.gameObject == targeObj)
            isCollision = false;
    }
    /// <summary>
    /// 是否激活对应组件
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <param name="tf">判断物体</param>
    /// <param name="isEnable">布尔值</param>
    public void IsEnableComponent<T>(Transform tf, bool isEnable) where T : MonoBehaviour
    {
        if (tf.TryGetComponent(out T component))
        {
            component.enabled = isEnable;
        }
    }
    public void IsEnableBoxCollider(Transform tf,bool isEnable)
    {
        if (tf.TryGetComponent(out BoxCollider bx))
        {
            bx.enabled = isEnable;
        }
    }
}

以上基本就是拖拽需要用到的代码了,有需要的自行判断使用。

下面是项目中进行调用的方法,并没有另起脚本,所以只贴方法。

因为要依次调用所以脚本默认不激活,当激活的时候挂载的物体会激活发光组件

引擎内物体布置如下,Interaction是交互组,obj为被拖拽物体,Targe为目标物体

申明函数并挂载相应物体后,以队列前两个为一组,当拖拽完成后将其移除队列并开启下一组交互

public GameObject[] Interactions;//存放交互组
public List<OnDragObj> InteractionDrag = new List<OnDragObj>();//存放被拖拽物体
public UnityAction OnInteractionAfterEvent;//交互结束后事件
public UnityAction monoFunc; //帧事件
    /// <summary>
    /// 交互(队列前两个)
    /// </summary>
    /// <param name="callback">交互结束事件</param>
    public void InteractionEvent(UnityAction callback)
    {
        //激活被拖拽物体身上的拖拽脚本
        InteractionDrag[0].enabled = true;
        InteractionDrag[1].enabled = true;
        //设置交互结束事件
        OnInteractionAfterEvent = callback;
        //添加帧事件
        monoFun+=InteractionOver;
    }
    /// <summary>
    /// 交互结束
    /// </summary>
    /// <param name="callback"></param>
    public void InteractionOver()
    {
        //当队列中的第一第二个物体都完成了拖拽,拖拽完成isArriveTarge为true
        if (InteractionDrag[0].isArriveTarge && InteractionDrag[1].isArriveTarge)
        {
            //移除帧事件
            monoFun-=InteractionOver;
            //移除队列前两个物体
            InteractionDrag.Remove(InteractionDrag[1]);
            InteractionDrag.Remove(InteractionDrag[0]);
            //执行交互结束事件
            OnInteractionAfterEvent?.Invoke();
        }
    }
    private void Update()
    {
       monoFunc?.Invoke();
    }

调用方法


    Interactions[0].SetActive(true);
    InteractionEvent(() => 
    {
       Interactions[1].SetActive(true);
       InteractionEvent(() => 
        {
           Interactions[2].SetActive(true);
           InteractionEvent(() => 之后的事件);
        });
    });

实现效果图如下 

    /// <summary>
    /// 交互(队列第一个)
    /// </summary>
    /// <param name="callback"></param>
    public void InteractionEvent0(UnityAction callback)
    {
        InteractionDrag[0].enabled = true;
        OnInteractionAfterEvent = callback;
        monoFun+=InteractionOver0;
    }
    /// <summary>
    /// 交互结束
    /// </summary>
    /// <param name="callback"></param>
    public void InteractionOver0()
    {
        if (InteractionDrag[0].isArriveTarge)
        {
            monoFun-=InteractionOver0;
            InteractionDrag.Remove(InteractionDrag[0]);
            OnInteractionAfterEvent?.Invoke();
        }
    }
InteractionEvent0(() => 
            InteractionEvent0(() => 
            InteractionEvent0(() => 
            InteractionEvent0(() => 
            InteractionEvent0(() => 之后执行事件)))));

 菜鸟程序一枚,第一次记录博客,写不清楚的地方还望见谅。

用到的发光组件:(12条消息) HighlightPlus8.0资源-CSDN文库

线框材质:(12条消息) 将Unity内三维物体线框化资源-CSDN文库

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要实现功能,可以使用HTML5中的drag and drop API。这个API提供了一些事件,可以用来实现和放置元素的交互。 具体步骤如下: 1. 给需要的元素添加draggable属性,值为true。 2. 监听该元素的dragstart事件,在事件处理函数中设置数据传输,可以使用event.dataTransfer.setData()方法,来传输数据。 3. 监听放置目标元素的dragover事件,并在事件处理函数中阻止默认行为,以允许放置元素。 4. 监听放置目标元素的drop事件,在事件处理函数中获取传输的数据,并执行相应操作。 具体实现过程可以参考如下示例代码: ```html <!-- 源元素 --> <div id="drag-source" draggable="true">我</div> <!-- 放置目标元素 --> <div id="drop-target">放置目标</div> <script> var dragSource = document.getElementById('drag-source'); var dropTarget = document.getElementById('drop-target'); // 监听dragstart事件,设置数据传输 dragSource.addEventListener('dragstart', function(event) { // 设置传输数据 event.dataTransfer.setData('text', '我是的数据'); }); // 监听dragover事件,阻止默认行为 dropTarget.addEventListener('dragover', function(event) { event.preventDefault(); }); // 监听drop事件,获取传输的数据并执行操作 dropTarget.addEventListener('drop', function(event) { // 获取传输的数据 var data = event.dataTransfer.getData('text'); // 在放置目标元素中预览数据 dropTarget.innerText = data; }); </script> ``` 在上面的示例代码中,当源元素被时,会设置传输的数据为字符串"我是的数据"。当把源元素到放置目标元素上时,会触发dragover事件,我们在事件处理函数中阻止了默认行为。当源元素在放置目标元素上方放置并释放鼠标时,会触发drop事件,我们在事件处理函数中获取了传输的数据,并把它预览在放置目标元素中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值