unity拖拽的三种实现方式

31 篇文章 0 订阅

第一种

使用条件:
1.场景中要有EventSystem
2.脚本引用命名空间using UnityEngine.EventSystems;
3.脚本继承自MonoBehaviour
4.脚本要实现接口IBeginDragHandler,IDragHandler,IEndDragHandler(第三个接口不是必须的)
5.仅对UGUI有效,ui的image组件的RaycastTarget必须勾选上

using UnityEngine;
using UnityEngine.EventSystems;
public class Test : MonoBehaviour,IBeginDragHandler, IDragHandler,IEndDragHandler
{
    
    private Vector3 offset;
    public void OnBeginDrag(PointerEventData eventData)
    {
        //开始拖拽的时候记录偏移量
        Vector3 v3;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(GetComponent<RectTransform>(),
            eventData.position, eventData.enterEventCamera, out v3);
        offset = transform.position-v3;
        
    }

    public void OnDrag(PointerEventData eventData)
    {
        transform.position = Input.mousePosition+offset;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        throw new System.NotImplementedException();
    }
}

第二种

使用条件:
1.可用于3d物体和worldspace模式的画布
2.被拖拽的物体必须挂上碰撞器,ui的碰撞器要尽量包裹住UI同时,碰撞器的size.z不要太“厚”

using UnityEngine;

public class Test1 : MonoBehaviour
{
    //偏移量
    private Vector3 offset = Vector3.zero;
    private float z;
    private void OnMouseDown()
    {
        z = Vector3.Dot(transform.position - Camera.main.transform.position, Camera.main.transform.forward);
        //也可以是z= Camera.main.WorldToScreenPoint(transform.position).z;
        //debug一下就知道这两个z是一样的
        //保持鼠标的屏幕坐标的z值与被拖拽物体的屏幕坐标的z保持一致
        Vector3 v3 = new Vector3(Input.mousePosition.x, Input.mousePosition.y, z);
        //得到鼠标点击位置与物体中心位置的差值
        offset = transform.position - Camera.main.ScreenToWorldPoint(v3);
    }
    private void OnMouseDrag()
    {
        //时刻保持鼠标的屏幕坐标的z值与被拖拽物体的屏幕坐标保持一致
        Vector3 v3 = new Vector3(Input.mousePosition.x, Input.mousePosition.y, z);
        //鼠标的屏幕坐标转换为世界坐标+偏移量=物体的位置
        transform.position = Camera.main.ScreenToWorldPoint(v3) + offset;
    }

}

第三种

使用条件
1.3d物体和worldspace模式的画布UI
2.必须有碰撞器

using UnityEngine;

public class Test2 : MonoBehaviour
{
    //1.3d物体和worldspace模式的画布UI
    //2.必须有碰撞器
    Vector3 offset;
    Vector3 hitpoint;
    RaycastHit hit;
    Ray ray;
    float z;
    private bool mIsDrag = false;
    private void Update()
    {
        ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Input.GetMouseButtonDown(0))
        {
            if (Physics.Raycast(ray,out hit))
            {
                mIsDrag = true;
                z = Vector3.Dot(hit.transform.position - Camera.main.transform.position,
                    Camera.main.transform.forward);
                //也可写z = Camera.main.WorldToScreenPoint(hit.transform.position).z,两者是一样的
                offset = hit.transform.position - Camera.main.ScreenToWorldPoint(new Vector3
                    (Input.mousePosition.x, Input.mousePosition.y,z));
            }
        }
        if (Input.GetMouseButton(0))
        {
            if (mIsDrag)
            {
                hit.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(
                    Input.mousePosition.x,Input.mousePosition.y, z))+offset;
            }
        }
        if (Input.GetMouseButtonUp(0))
        {
            mIsDrag = false;
        }
    }
}

2021.5.28补充一种拖拽方式,其原理还是射线,不过我觉得他更适合VR手柄,而且比较简单,没有太多的转换,使用条件和第三种一样

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

public class NewBehaviourScript : MonoBehaviour
{
    float mDistance;
    Ray mRay;
    RaycastHit mHit;
    GameObject mCurrentDragGo;
    Vector3 offset = Vector3.zero;
    public GameObject mHand;
    // Update is called once per frame
    void Update()
    {

       
    }
    //鼠标模拟
    void MouseInput()
    {
        mRay = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Input.GetMouseButtonDown(0))
        {
            if (Physics.Raycast(mRay, out mHit))
            {
                mDistance = Vector3.Distance(mRay.origin, mHit.point);
                mCurrentDragGo = mHit.transform.gameObject;
                offset = mCurrentDragGo.transform.position - mHit.point;
            }
        }
        if (Input.GetMouseButton(0))
        {
            if (mCurrentDragGo)
            {
                Vector3 vector3 = mRay.GetPoint(mDistance);
                Debug.Log(vector3);
                mCurrentDragGo.transform.position = vector3 + offset;
            }
        }
        if (Input.GetMouseButtonUp(0))
        {
            mCurrentDragGo = null;
            mDistance = 0;
        }

    }

    //手柄输入
    void HandInput()
    {
         mRay = new Ray(mHand.transform.position, mHand.transform.forward);
        if (Input.GetKeyDown(KeyCode.Q))
        {
            if (Physics.Raycast(mRay, out mHit))
            {
                mDistance = Vector3.Distance(mRay.origin, mHit.point);
                mCurrentDragGo = mHit.transform.gameObject;
                offset = mCurrentDragGo.transform.position - mHit.point;
            }
        }
        if (Input.GetKey(KeyCode.Q))
        {
            if (mCurrentDragGo)
            {
                Vector3 vector3 = mRay.GetPoint(mDistance);
                mCurrentDragGo.transform.position = vector3 + offset;
            }
        }
        if (Input.GetKeyUp(KeyCode.Q))
        {
            mCurrentDragGo = null;
            mDistance = 0;
        }
        if(Input.GetKey(KeyCode.LeftArrow))
        {
            mHand.transform.position+=Time.deltaTime*10*Vector3.left;
        }
        if(Input.GetKey(KeyCode.RightArrow))
        {
            mHand.transform.position+=Time.deltaTime*10*Vector3.right;
        }
    }
}

  • 12
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带酒书生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值