欢迎来到我的博客小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

学Unity的猫之物理碰撞(十)

  |   0 评论   |   0 浏览

10.1 流浪喵星

2020年,喵星所在的拉姆达星系中,巨大的鲁特恒星即将毁灭,已经不适合喵星人生存,面对绝境,喵星人开启了 “流浪喵星” 计划,试图带着喵星一起逃离拉姆达星系,寻找喵星人新的家园。 然而,喵星在靠近纳美星的时候被强大的引力吸住,马上就要撞上去了,情况十分危急。

皮皮:“呼叫铲屎官,呼叫铲屎官,只剩最后1分钟了。”

我:“请点燃纳美星!”

皮皮:“来不及了。”

我:“以下是命令 :活下去!”皮皮:“奇迹出现了,喵星直接穿透了纳美星。”

10.2 碰撞的必要条件

皮皮:“铲屎官,你刚刚是怎么做到的?”

我:“最后关头,我将纳美星的碰撞器禁用了,避免了这次物理碰撞。”

Unity3D内置物理引擎,可以模拟物理效果。典型的一个物理效果就是碰撞。 两个物体发生物理碰撞的必要条件是:两个物体都带有Collider(碰撞器)组件,其中一个物体带有Rigidbody(刚体)组件,并且是运动的物体带有Rigidbody组件。

10.2.1 Collider,碰撞器组件

Collider,即碰撞器。Unity中提供了各种形状的碰撞器组件。点击AddComponent,可以看到如下的各种碰撞器组件,这些碰撞器组件名字带2D的都是继承自Collider2D类,名字没带2D的都继承自Collider类,一般3D物体的使用Collider碰撞器,2D物体使用Collider2D碰撞器。我们通过3D Object菜单创建的几何体都默认带了相应的碰撞器组件。比如创建球体Sphere,它会自带球形碰撞器组件Sphere Collider

10.2.2 Rigidbody,刚体组件

Rigidbody,刚体组件,刚体能让你的游戏对象被物理引擎所控制,它能通过受到推力和扭力来实现真实的物理表现效果。

我们可以通过给刚体施加一个力来改变一个它的运动状态:

Rigidbody rigidBody = gameObject.GetComponent<Rigidbody>();

rigidBody.AddForce(new Vector3(1, 0, 0));

刚体受到力的作用,会改变运动状态。假设初始状态是禁止的,那么施加一个力之后,刚体会动起来。动起来的速度与刚体受到的力成正比,与刚体的质量成反比。RigidbodyMass属性就是刚体的质量。使用代码设置刚体的质量:

rigidBody.mass = 1;

我们要可以直接给刚体设置速度:

rigidBody.velocity = new Vector3(1, 0, 0);

另外,还可以设置角速度:

rigidBody.angularVelocity = new Vector3(0, 1, 0);

有了角速度,物体就会开始旋转。刚体的运动状态还会受到空气阻力的影响,RigidbodyDrag属性就是刚体的空气阻力,默认为0,即空气阻力为0。通过代码设置刚体的空气阻力:

rigidBody.drag = 0;

物体的旋转受到角阻力Angular Drag的影响。通过代码设置刚体的角阻力:

rigidBody.angularDrag = 0.05f;

皮皮拿过鼠标,点击AddComponent,添加了刚体组件。刚体的属性如下:点击运行Unity皮皮:“怎么回事呀?球体直接垂直往下掉了。”

我:“因为Rigidbody有个Use Gravity属性,意思就是是否使用重力,默认是勾选着的,所以球体就受到重力作用直接垂直往下掉了。”去掉Use Gravity的勾选,移动球体,可以产生碰撞了,不过如果移动速度快一点,还是可以穿过去。皮皮:“这又是怎么回事呀?”

我:“因为我们是强行拖拉来移动刚体物体的,并不是由物理引擎来驱动移动,刚体的碰撞检测不是连续的。另外,被撞的物体是一个静态碰撞器,我们这样强行拉着刚体移动,只要速度稍快一些就会出现穿透现象。”

皮皮:“你解释一个问题,中间又引入了新的概念,什么是静态碰撞器?”

10.3 碰撞器类型

10.3.1 Static Collider,静态碰撞器

静态碰撞器是指只挂了Collider而没挂Rigidbody的游戏对象。这类对象会保持静止或者很轻微的移动。这类碰撞器被刚体碰撞后不会移动。 皮皮:“难怪刚刚被撞的另一个球不会动,因为它是一个静态碰撞器。”

10.3.2 Rigidbody Collider,刚体碰撞器

刚体碰撞器是指既挂了Collider又挂了Rigidbody的游戏对象。运动的刚体碰撞器可以与静态碰撞器发生碰撞,两个刚体碰撞器之间也可以发生碰撞。如果刚体碰撞器禁止不动,强行移动静态碰撞器去碰刚体碰撞器,此时并不会发生碰撞,因为禁止的刚体碰撞器会进入休眠状态。

10.3.3 Kinematic Rigidbody Collider,运动学刚体碰撞器

运动学刚体碰撞器是指在刚体碰撞器的基础上,激活了Kinematic的游戏对象。要移动这类游戏对象,要修改它的Transform组件(坐标或角度),而不能通过力。

我:“运动学刚体碰撞器是个非常懒惰和霸道的家伙,它不受力、重力或扭矩的影响,它去碰别人,它自己不会受到反作用力。所以你可以把运动学刚体碰撞器看成一个所向披靡的碰撞器,谁遇到它都不是对手。”

皮皮:“那如果两个运动学刚体碰撞器相互碰撞会怎样?”

我:“谁也不让谁,直接穿透过去。”

皮皮:“微信搜索公众号 [爱上游戏开发],回复 “资料”,免费领取 200G 学习资料!”

10.4 碰撞事件

MonoBehavior脚本中,我们可以通过OnCollisionEnterOnCollisionStayOnCollisionExit来处理收碰撞事件。其中collision参数是对方的碰撞器对象,脚本挂在两个碰撞体上都可以触发OnCollisionXXX

private void OnCollisionEnter(Collision collision)
{
    Debug.Log("碰撞进入");
}

private void OnCollisionStay(Collision collision)
{
    Debug.Log("碰撞中");
}

private void OnCollisionExit(Collision collision)
{
    Debug.Log("碰撞结束");
}

10.5 触发器事件

有时候我们并不想产生物理碰撞的效果,但是又想检测碰撞器之间的碰撞事件,这个时候就可以使用触发器。 触发器其实是碰撞器,只是勾选了Is Trigger。 在MonoBehavior脚本中,我们可以通过OnTriggerEnterOnTriggerStayOnTriggerExit来处理收碰撞事件。

private void OnTriggerEnter(Collider other)
{
    Debug.Log("触发进入");
}

private void OnTriggerStay(Collider other)
{
    Debug.Log("触发中");
}

private void OnTriggerExit(Collider other)
{
    Debug.Log("触发结束");
}

想要产生触发器事件,两个碰撞器中至少要有一个勾选了Is Trigger,并且其中一个要带Rigidbody组件。

皮皮:“触发器有什么应用吗?看起来不知道用在哪里。”

我:“举个简单的例子,你走近一个门的时候,要触发播放开门的动作,那么门就可以弄成触发器。门的碰撞体可以稍微调大一点,这样人就可以提前碰到触发器,触发开门动作。”

10.6 射线碰撞检测

皮皮:“可不可以实现一个鼠标拖动物体的功能,这样就可以直接用鼠标拖动喵星逃离兰姆达星系啦。”

我:“可以呀,原理很简单,点击鼠标左键,从摄像机的位置往里发射射线,检测到碰撞,则把碰撞体缓存到一个对象中,移动鼠标的时候,把鼠标坐标转成世界坐标赋值给刚刚的物体,实现鼠标抓取物体移动的效果,鼠标松开时,释放缓存对象。”

Demo工程如下,把下文的TouchAndMoveObj .cs脚本挂在某个GameObject即可,比如挂在Main Camera上。

运行效果:

TouchAndMoveObj .cs脚本代码如下:

using UnityEngine;

public class TouchAndMoveObj : MonoBehaviour
{
    private Transform m_targetTrans;
    private Camera cam;
    private float m_posZ;

    private void Start()
    {
        cam = Camera.main;
    }

    private void Update()
    {
        
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = cam.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100))
            {
                
                m_targetTrans = hit.transform;
                
                m_posZ = m_targetTrans.position.z - cam.transform.position.z;
            }
        }
        
        if (Input.GetMouseButtonUp(0))
        {
            
            m_targetTrans = null;
        }
        
        if (null != m_targetTrans && Input.GetMouseButton(0))
        {
            
            
            var targetPos = cam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, m_posZ)); ;
            
            m_targetTrans.position = targetPos;
        }
    }
}

标题:学Unity的猫之物理碰撞(十)
作者:shirlnGame
地址:https://mmzsblog.cn/articles/2021/01/11/1610371890407.html
-----------------------------
如未加特殊说明,此网站文章均为原创。
网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
公众号转载请联系网站首页的微信号申请白名单!

个人微信公众号 ↓↓↓                 

微信搜一搜爱上游戏开发