• Unity使用ConfigurableJoint实现物理拖拽物体


    我们如何在游戏中实现拖拽物体呢,如果仅仅是让拖拽坐标,可能没有物理效果,这里可以使用Joint来实现。

    场景

    首先我们在场景中放置道具。
    在这里插入图片描述
    如图,我们放置一个圆柱体Cylinder,一个Sphere球体,和地面。
    圆柱体就是我们要拖动的物体,红色球体是我们点击的位置,白色的地面放置圆柱体掉下去。

    我们在圆柱体上增加刚体,球体上也增加刚体,球体的Rig需要勾选运动学,因为Joint组件需要。

    我们要实现鼠标点击圆柱体,拖拽,圆柱体跟随鼠标左右上下移动。

    我们添加一个脚本CDrag挂在球体上。
    在这里插入图片描述
    变量HandRig就是球体的刚体。
    变量Target就是圆柱体。

    鼠标按下

    在Update中,我们先写鼠标点击事件。我们要做的事情就是鼠标按下后,我们发射射线检测是否碰到圆柱体,然后把红色的球体移动过去,并且给圆柱体增加ConfigurableJoint,把他们两个联系起来,这样圆柱体就跟随球体了。代码如下:

    	void Hand(float x, float y)
        {
            Vector3 at = new Vector3(x, y, myCamera.transform.position.z);
            Ray ray = myCamera.ScreenPointToRay(at);
            RaycastHit hit;
            Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 1f);
            bool b = Physics.Raycast(ray, out hit, 100f, 1 << LayerMask.NameToLayer("Default"));
            if (b && hit.collider != null && hit.collider.name.Equals("Cylinder"))
            {
                HandRig.transform.position = hit.point;
                if (joint != null)
                    Destroy(joint);
                joint = target.gameObject.AddComponent<ConfigurableJoint>();
                joint.connectedBody = HandRig;
                joint.xMotion = ConfigurableJointMotion.Locked;
                joint.yMotion = ConfigurableJointMotion.Locked;
                joint.zMotion = ConfigurableJointMotion.Locked;
                handupdis = Vector3.Distance(hit.point, myCamera.transform.position);
            }
        }
        
    	void Update()
        {
    
            if (Input.GetMouseButtonDown(0))
            {
                Hand(Input.mousePosition.x,Input.mousePosition.y);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    我们看到,在射线碰到圆柱体后,我们把红球改到了碰撞点位置,并且给target(圆柱体)增加了ConfigurableJoint,并且让他connectedBody到红球,并且设置x,y,z可以自由移动。最后handupdis是为了下面的移动准备的。

    鼠标移动

    然后我们再来处理移动
    当我们移动的时候,我们只要移动球体,那么因为Joint被绑定到球体了,他也会跟着移动了。

    		if (Input.GetMouseButton(0))
            {
                Move(Input.mousePosition);
            }
    
    • 1
    • 2
    • 3
    • 4
    	private void Move(Vector3 pos)
        {
            pos.z = handupdis;
            Vector2 world = myCamera.ScreenToWorldPoint(pos);
            
            HandRig.transform.position = world;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们来看看效果。
    请添加图片描述
    有没有发下一个问题,红球点击圆柱体下面的时候,被拾取的点还是在顶部,我们需要计算锚点。

    增加这行代码就舒服多了。

    joint.anchor = joint.transform.InverseTransformPoint(hit.point);
    
    • 1

    最后

    我们把鼠标放开也一起写了,放上全部代码。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //UTF8支持
    public class CDrag : MonoBehaviour
    {
        [SerializeField] Rigidbody HandRig;
        [SerializeField] Transform target;
        Camera myCamera;
        ConfigurableJoint joint;
    
        float handupdis;
        Vector2 startpos;
        // Start is called before the first frame update
        void Start()
        {
            myCamera = Camera.main;
        }
    
        void Hand(float x, float y)
        {
            Vector3 at = new Vector3(x, y, myCamera.transform.position.z);
            Ray ray = myCamera.ScreenPointToRay(at);
            RaycastHit hit;
            Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red, 1f);
            bool b = Physics.Raycast(ray, out hit, 100f, 1 << LayerMask.NameToLayer("Default"));
            if (b && hit.collider != null && hit.collider.name.Equals("Cylinder"))
            {
                HandRig.transform.position = hit.point;
                if (joint != null)
                    Destroy(joint);
                joint = target.gameObject.AddComponent<ConfigurableJoint>();
                joint.connectedBody = HandRig;
                joint.xMotion = ConfigurableJointMotion.Locked;
                joint.yMotion = ConfigurableJointMotion.Locked;
                joint.zMotion = ConfigurableJointMotion.Locked;
                joint.anchor = joint.transform.InverseTransformPoint(hit.point);
                handupdis = Vector3.Distance(hit.point, myCamera.transform.position);
            }
        }
    
        private void Move(Vector3 pos)
        {
            pos.z = handupdis;
            Vector2 world = myCamera.ScreenToWorldPoint(pos);
            
            HandRig.transform.position = world;
        }
        void Update()
        {
    
            if (Input.GetMouseButtonDown(0))
            {
                Hand(Input.mousePosition.x,Input.mousePosition.y);
            }
            if (Input.GetMouseButton(0))
            {
                Move(Input.mousePosition);
            }
            if (Input.GetMouseButtonUp(0))
            {
                Destroy(joint);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    最终效果如下:
    请添加图片描述
    最后,Joint家族里还可以使用其他的Joint来实现,例如SpringJoint,那就带有弹簧效果了,原理都是一样和一个刚体链接起来就可以了。

  • 相关阅读:
    计算机网络 网络原理之Http
    [CISCN 2019初赛]Love Math - RCE(异或绕过)
    Linux创建逻辑卷并扩容(超详细)
    JAVA【设计模式】责任链模式
    【电子通识】案例:采用电阻分压式采样电压的设计注意事项
    PMP每日一练 | 考试不迷路-9.13(包含敏捷+多选)
    vue 页面监听vuex state值的变化
    C 语言超全练习题(一): 初识C语言
    SSH详解
    打造千万级流量秒杀第十二课 高性能缓存:多级缓存是如何提升服务性能的?
  • 原文地址:https://blog.csdn.net/thinbug/article/details/126128630