第二十七章 Unity碰撞体Collision(下)

这篇具有很好参考价值的文章主要介绍了第二十七章 Unity碰撞体Collision(下)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本章节我们继续研究碰撞体,并且探索一下碰撞体与刚体之间的联系。我们回到之前的工程,然后给我们的紫色球体Sphere1也添加一个刚体组件。如下所示

第二十七章 Unity碰撞体Collision(下)

此时,两个球体都具备了碰撞体和刚体组件。接下来,我们Play运行查看效果

第二十七章 Unity碰撞体Collision(下)

我们发现,黄球碰撞紫球之后,两者都向右移动了,并且黄色还发出的角度变化。之所以这样,肯定是刚体组件作用的原因。应该还是依据动能公式进行各种计算,其中影响的因素包括双方的质量,以及运动方的移动速度等等。如果指向让两个球体在X轴上移动的话,我们可以借助刚体的Constraints下的Freeze Position来实现,我们要做的就是勾选Y轴和Z轴,这样球体在受到刚体影响进行移动的时候,就只会在X轴上发生移动了。

第二十七章 Unity碰撞体Collision(下)

大家可以将两个球体像上图那样设置,然后运行一下,查看效果,这里就不演示了。

有时候,我们需要在两个球体发生碰撞的时候做一些处理,比如播放一个碰撞火花效果。我们应该怎么办呢?这里要给大家介绍一个方法。脚本系统可以使用 OnCollisionEnter 方法检测何时发生碰撞。接下来,我们给紫球添加一个C#脚本(CollisionScript.cs),在这个脚本中我们只打印相互碰撞的两个游戏对象的名称即可。如下所示:

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

public class CollisionScript : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)
    {
        // 打印碰撞游戏对象的名称
        Debug.Log("当前对象 " + gameObject.name + " 与 " + collision.gameObject.name + " 发生碰撞");
    }
}

方法OnCollisionEnter 被传入的参数为 Collision 类,该类中的gameObject变量可以获取到参与碰撞的游戏对象,进而可以获取到碰撞游戏对象的基本信息。同时,我们还可以通过Collision类的GetContact 或 GetContacts方法来获取碰撞点,该方法会返回ContactPoint对象,这个ContactPoint对象中point属性就是一个Vector3类型的位置点。接下来,我们将上面的脚本附加到紫球上面,然后Play运行当前工程。

第二十七章 Unity碰撞体Collision(下)

由于我们的地面Plane也存在碰撞体组件,因此工程运行后就打印了紫球Sphere1与地面Plane的碰撞日志信息,然后就是当黄球Sphere2碰撞紫球Sphere1的时候,打印出紫球与黄球的碰撞日志信息。请注意,紫球是被碰撞的游戏物体哦。接下来,我们在写一个脚本(CollisionScript2.cs),并将该脚本附加到黄球上面,如下所示:

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

public class CollisionScript2 : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)
    {
        // 打印碰撞游戏对象的名称
        Debug.Log("碰撞游戏对象的名称 " + collision.gameObject.name + " 发生碰撞");
    }
}

为了区分日志信息,我们上面的代码只打印了碰撞目标的名称,也就是紫球Sphere1 。然后,我们将这个脚本附加到黄球Sphere2上面,运行当前工程,如下所示:

第二十七章 Unity碰撞体Collision(下)

首先两个球体Sphere1和Sphere2都会与地面Plane发生碰撞,这个不是我们关注的。我们主要关注的是当黄球Sphere2与紫球Sphere1 发生碰撞的时候,两个脚本中的OnCollisionEnter都被触发了。而方法的参数Collision对象都代表了碰撞的对方。上图中第一个红色框日志信息就是黄球Sphere2输出的,它的碰撞对方自然就是紫球Sphere1了。而下面的红色框日志就是紫球Sphere1输出的,它直接输出自己与Sphere2发生碰撞。其实,除了OnCollisionEnter方法之外,还有OnCollisionStay和OnCollisionExit两个方法,从名称上面来看,一个是碰撞中的调用方法(碰撞可能会持续发生),另一个是碰撞结束的调用方法(一次性)。而我们上面的OnCollisionEnter方法则是碰撞开始调用的方法(一次性)。我们可以根据我们要实现的效果来选择使用其中任意方法。

使用刚体组件能够帮助我们完成游戏对象的运动效果,然后配合碰撞体组件可以帮助我们完成碰撞后的运动效果。这两个组件基本上可以帮助我们模拟现实世界中物体的物理碰撞和移动。但是,有时候,我们还是希望通过代码来完成移动或者碰撞后的移动。比如上面中两个球体碰撞后,黄球弹了起来,这个可能不是我们想要的效果。因此我们不得不做轴向的限制。但是,如果使用代码控制的话,我们就可以简简单单的让球体在X轴上移动即可。如何使用代码控制呢?我们之前也讲过,我们可以启动刚体的“Is Kinematic”属性,使用代码来控制游戏对象的移动或旋转。因此,我们就先启用紫球Sphere1的“Is Kinematic”属性。这样的话,紫球应该就不能受物理引擎而发生运动了,运行工程如下:

第二十七章 Unity碰撞体Collision(下)

接下来,我们开始Play运行工程

第二十七章 Unity碰撞体Collision(下)

正如我们预想的那样,紫球不在向右运动,而且黄球由于紫球碰撞体的阻挡,也停止了移动。接下来,我们继续启动黄球Sphere2的“Is Kinematic”属性。

第二十七章 Unity碰撞体Collision(下)

这样的话,我们之前施加的力Constant Force组件就不能其作用了,我们应该使用脚本控制黄球向右移动,我们需要向“CollisionScript2.cs”脚本中添加如下代码:

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.D))
        transform.Translate(new Vector3(0.5f, 0, 0));
    }

我们使用按键“D”来控制黄球向右移动去碰撞紫球,运行工程如下所示:

第二十七章 Unity碰撞体Collision(下)

我们发现,黄球可以穿透紫球,并且紫球也没有任何的反应。并且我们的控制台也没有任何的日志输出。这说明,当我们启用刚体的“Is Kinematic”属性,而由代码去控制游戏对象进行移动或旋转的时候,现实世界中的碰撞效果全部消失了,并且OnCollisionEnter方法也没有被触发。那我们应该怎么办呢?首先,我们应该明白一点的是,我们启用刚体的“Is Kinematic”属性之后,就不能够让Unity物理引擎来控制游戏对象的移动或旋转了。正如我们使用按键“D”来控制黄球移动一个道理。同样的,紫球在受到碰撞的时候,也需要我们使用代码来控制它的移动和旋转。但是,我们怎么知道两球碰撞的时间点呢,OnCollisionEnter方法也失效了啊。我们需要通过另一个方法来执行碰撞后的运动效果,就是碰撞体里面的“Is Trigger”属性。接下来,我们就开启紫球Sphere1碰撞体里面的“Is Trigger”属性,截图如下:

第二十七章 Unity碰撞体Collision(下)

然后,我们需要在紫球的“CollisionScript.cs”脚本中添加“OnTriggerEnter”方法。该方法的参数为Collider 对象(与OnCollisionEnter方法参数Collision不一样哦)。这里的Collider 对象同样可以通过gameObject来获取碰撞对象。具体代码如下: 

    void OnTriggerEnter(Collider other)
    {
        Debug.Log("当前对象被" + other.gameObject.name + "碰撞到了!");
    }

接下来,我们Play运行当前工程。

第二十七章 Unity碰撞体Collision(下)

我们终于看到OnTriggerEnter方法被触发了,打印出了黄球Sphere2了。那么,我们继续给黄球添加OnTriggerEnter方法也试一试,如下所示:

    void OnTriggerEnter(Collider other)
    {
        Debug.Log("碰撞到了 " + other.gameObject.name + " 对象!");
    }

接下来,我们就Play运行当前工程

第二十七章 Unity碰撞体Collision(下)

我们发现两球的OnTriggerEnter方法都被触发了,正确打印出彼此对方的名称。除了OnTriggerEnter方法之前,还有OnTriggerExit和OnTriggerStay两个方法。看名称就知道,一个是碰撞结束方法,另一个是碰撞中的方法(碰撞也是可持续的哦)。接下来,我们就借助这三个方法来控制黄球的运行。例如,当发生碰撞后,黄球就停止移动。我们可以在“CollisionScript2.cs”脚本中设置一个碰撞进行时的变量isTriggerFlag=false,在OnTriggerEnter方法中设置为true,在OnTriggerExit方法中设置为false,当我们使用按键D进行移动的时候,需要参考isTriggerFlag来进行移动,具体完整代码如下:

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

public class CollisionScript2 : MonoBehaviour
{

    // 碰撞进行时变量
    private bool isTriggerFlag = false;

    void Update()
    {
        // 移动加入isTriggerFlag条件
        if (Input.GetKeyDown(KeyCode.D) && !isTriggerFlag)
        transform.Translate(new Vector3(0.5f, 0, 0));
    }

    void OnCollisionEnter(Collision collision)
    {
        // 打印碰撞游戏对象的名称
        Debug.Log("碰撞游戏对象的名称 " + collision.gameObject.name + " 发生碰撞");
    }

    void OnTriggerEnter(Collider other)
    {
        isTriggerFlag = true;
        Debug.Log("碰撞到了 " + other.gameObject.name + " 对象!");
    }

    void OnTriggerExit(Collider other)
    {
        isTriggerFlag = false;
    }
}

其实在上面的代码中,OnCollisionEnter方法已经失去了意义,可以删除掉了。

我们运行当前工程,当按下按键D移动黄球的时候,碰到紫球就不在移动了。

第二十七章 Unity碰撞体Collision(下)

那么紫球该如何移动呢,我们可以在紫球的OnTriggerStay方法中进行移动,代码如下:

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

public class CollisionScript : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)
    {
        // 打印碰撞游戏对象的名称
        Debug.Log("当前对象 " + gameObject.name + " 与 " + collision.gameObject.name + " 发生碰撞");
    }

    void OnTriggerEnter(Collider other)
    {
        Debug.Log("当前对象被" + other.gameObject.name + "碰撞到了!");
    }

    void OnTriggerStay(Collider other)
    {
        // 去掉地面碰撞的情况
        if (other.gameObject.name == "Sphere2")
        transform.Translate(0.1f, 0, 0);
    }
}

其实在上面的代码中,OnCollisionEnter方法已经失去了意义,可以删除掉了。

我们运行当前工程,当按下按键D移动黄球的时候,碰到紫球后,黄球停止移动且紫球向右缓慢移动,两者碰撞结束,黄球又可以移动……

第二十七章 Unity碰撞体Collision(下)

静态碰撞体和动态碰撞体:

我们可以将碰撞体添加到没有刚体组件的游戏对象,从而创建场景的地板、墙壁和其他静止物体。这些被称为静态碰撞体(Static Collider)。相反,具有刚体的游戏对象上的碰撞体称为动态碰撞体(Rigidbody Collider)。如果我们在动态碰撞体上开启了IsKinematic 属性,那么就是运动碰撞体 (Kinematic Rigidbody Collider)。在游戏场景中,以上三种碰撞体都会出现,如何判断三者之间的碰撞关系呢?重点在于OnTriggerEnter和OnCollisionEnter方法的选择。我们可以这样的理解,刚体是基于碰撞体之上的运动组件。刚体可以帮助我们完成游戏物体的运动以及碰撞后的运动效果,同时提供OnCollisionEnter方法让我们可以处理碰撞后的游戏代码逻辑。如果我们不想让刚体来完成游戏的运动,也就是启用刚体的“Is Kinematic”属性,那么我们则需要使用代码来控制游戏物体的运动。为了能够获取碰撞发生,我们需要启用碰撞体的“Is Trigger”属性,Unity会在碰撞后调用OnTriggerEnter方法。因此,我们对游戏对象碰撞后的移动和旋转操作应该放置到OnTriggerEnter方法中。

但是OnTriggerEnter方法执行是有条件的,如下所示:

1、两个物体都必须有碰撞体组件;

2、其中一个物体的碰撞体的IsTrigger属性必须勾上;

3、最重要的一点,其中一个物体必须有刚体组件。如果是一个运动的物体去碰撞一个静止的物体,则刚体组件必须加在运动的物体上,否则无法触发OnOnTriggerEnter方法。

最后介绍一下Layer层和碰撞体的关系,层与层之间是否发生碰撞。我们点击菜单栏Edit->Project Setting->Physics,然后找到Layer Collision Matrix(层碰撞矩阵)选项。在Layer Collision Matrix下就会显示所有层,层与层之间是否可以发生碰撞检测。默认是都发生碰撞检测的,也就是勾选状态。如果不想让两个层进行碰撞检测,取消两层交叉的勾选框即可。

第二十七章 Unity碰撞体Collision(下)

本课程涉及的内容已经共享到百度网盘:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id文章来源地址https://www.toymoban.com/news/detail-488411.html

到了这里,关于第二十七章 Unity碰撞体Collision(下)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第二十七章 控制到 XML 模式的映射 - 影响架构的编译器关键字

    VALUELLIST 向类型添加 enumeration 限制。考虑下面的类: 下面显示了该类的架构: XMLFractionDigits 适用于 %Numeric 。此参数对应于 fractionDigits 构面,如以下片段所示: XMLTotalDigits 适用于 %Numeric 属性或 %Integer 属性。此参数对应于 totalDigits 方面,如以下片段所示: XMLLISTPARAMETER 适用

    2024年02月04日
    浏览(28)
  • 【正点原子STM32连载】 第二十七章 RTC实验摘自【正点原子】APM32E103最小系统板使用指南

    1)实验平台:正点原子APM32E103最小系统板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban 本章介绍APM32E103实时时钟(RTC)的使用,实时时钟能为系统提供一个准确的时间,即时系统复位或主

    2024年01月19日
    浏览(53)
  • Unity常用方法-- Collision碰撞检测

    LayerMask 描述 指定要在 Physics.Raycast 中使用的层。 代码 Physics2D.Raycast 函数结构 public static RaycastHit2D Raycast  (Vector2 origin,  Vector2 direction, float distance= Mathf.Infinity, int layerMask= DefaultRaycastLayers, float minDepth= -Mathf.Infinity, float maxDepth= Mathf.Infinity); 参数 origin 射线在 2D 空间中的

    2024年02月03日
    浏览(34)
  • 【正点原子FPGA连载】第二十七章 MDIO接口读写测试实验 摘自【正点原子】DFZU2EG/4EV MPSoC 之FPGA开发指南V1.0

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html 在以太网通信中,设备之间的物理层链路均由PHY芯片(物理层芯片,本文指YT8521)建立。PHY芯片有一个配置接

    2024年02月09日
    浏览(52)
  • 【正点原子FPGA连载】 第二十七章OV5640摄像头LCD显示 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html OV5640是OmniVision(豪威科技)公司生产的一颗CMOS图像传感器,该传感器功耗低、分辨率高以及采集速率快,主

    2024年02月16日
    浏览(50)
  • C语言第二十七弹---内存函数

    ✨ 个人主页:  熬夜学编程的小林 💗 系列专栏:  【C语言详解】 【数据结构详解】 内存函数 1、memcpy 使用和模拟实现 2、memmove 使用和模拟实现 3、memset 函数的使用 4、memcmp 函数的使用 总结 前面两弹讲解了字符函数和字符串函数,但是在我们实际运用中不仅仅只有这些

    2024年02月19日
    浏览(29)
  • 第十七章 Unity 预制件prefab(下)

    本章节我们来讲解如何编辑预制体文件。这里介绍三种打开编辑预制件的方式。第一就是通过预制件的实例游戏对象的Inspector检视面板上面的预制件“打开”按钮。 第二就是在Project工程面板中选中预制件文件(Cube.prefab),然后在Inspector检视面板中点击“打开预制件”。 第

    2024年02月04日
    浏览(23)
  • 【LeetCode75】第二十七题(933)最近的请求次数

    目录 题目: 示例: 分析: 代码+运行结果: 首先这是LeetCode75里第一道设计类的题目,这种类型的题目会比较新颖,就是按照题目要求来设计一个类。然后测试用例是模拟真实调用类的成员函数的。 这道题也算是简单题,整个类除了构造函数以外就一个成员函数,测试用例

    2024年02月13日
    浏览(33)
  • 学C的第二十七天【指针的进阶(三)】

    ========================================================================= 相关代码gitee自取 :C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 学C的第二十六天【指针的进阶(二)】_高高的胖子的博客-CSDN博客  ================================

    2024年02月16日
    浏览(35)
  • 【从零开始学习JAVA | 第二十七篇】JAVA期末练习(PTA)

    目录 前言: R7-5 Count the letters in a string (统计字符串中的字符) R7-1 找素数 R7-3 电话号码同步(Java) 总结:         临近期末,我也更新一下PTA上的JAVA大题,希望各位都可以考出一个好的成绩。 (Count the letters in a string) (统计字符串中的字符) Write a method that counts th

    2024年02月16日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包