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);
        }
    }

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

鼠标移动

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

		if (Input.GetMouseButton(0))
        {
            Move(Input.mousePosition);
        }
	private void Move(Vector3 pos)
    {
        pos.z = handupdis;
        Vector2 world = myCamera.ScreenToWorldPoint(pos);
        
        HandRig.transform.position = world;
    }

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

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

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

最后

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

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);
        }
    }
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Thinbug

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

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

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

打赏作者

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

抵扣说明:

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

余额充值