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

news2024/9/28 19:25:53

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

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

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

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

有时候,我们需要在两个球体发生碰撞的时候做一些处理,比如播放一个碰撞火花效果。我们应该怎么办呢?这里要给大家介绍一个方法。脚本系统可以使用 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运行当前工程。

由于我们的地面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上面,运行当前工程,如下所示:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

我们发现两球的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移动黄球的时候,碰到紫球就不在移动了。

那么紫球该如何移动呢,我们可以在紫球的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移动黄球的时候,碰到紫球后,黄球停止移动且紫球向右缓慢移动,两者碰撞结束,黄球又可以移动……

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

我们可以将碰撞体添加到没有刚体组件的游戏对象,从而创建场景的地板、墙壁和其他静止物体。这些被称为静态碰撞体(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下就会显示所有层,层与层之间是否可以发生碰撞检测。默认是都发生碰撞检测的,也就是勾选状态。如果不想让两个层进行碰撞检测,取消两层交叉的勾选框即可。

本课程涉及的内容已经共享到百度网盘:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/486871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第二十六章 Unity碰撞体Collision(上)

在游戏世界中,游戏物体之间的交互都是通过“碰撞接触”来进行交互的。例如,攻击怪物则是主角与怪物的碰撞,触发机关则是主角与机关的碰撞。在DirectX课程中,我们也大致介绍过有关碰撞检测的内容。游戏世界中的3D模型的形状是非常复…

浅谈区块链1.0-比特币

1. 比特币解决的问题 高度自治:国际经济危机无国界贸易:不同国家进行的贸易或者不同平台进行贸易 不可窜改:例如银行交易可能会被窜改数据 隐私安全:传统汇款方式会暴露你的个人信息,一旦数据库被别人入侵&#xff0c…

android基础知识复习

架构: 应用框架层(Java API Framework)所提供的主要组件: 名称功能描述Activity Manager(活动管理器)管理各个应用程序生命周期,以及常用的导航回退功能Location Manager(位置管理器…

SpringBoot整合Mybatis-plus实现多级评论

在本文中,我们将介绍如何使用SpringBoot整合Mybatis-plus实现多级评论功能。同时,本文还将提供数据库的设计和详细的后端代码,前端界面使用Vue2。 数据库设计 本文的多级评论功能将采用MySQL数据库实现,下面是数据库的设计&…

Boonz-KeygenMe#1(★★★)

运行程序 错误: 查壳 没有壳,是汇编写的程序 载入OD 前面是在读取输入内容,到这里开始做计算了 分析 首先遍历了用户名,计算结果保存在EBX,在存放到 0x40E0F8 对EBX中的值再次计算,最后结果保存到 …

JavaFX: Java音乐播放读取歌词

JavaFX: Java音乐播放读取歌词 1、lrc歌词文件2、解析lrc歌词2.1 读取每行歌词2.2 解析歌词时间标签Time-tag2.3 解析歌词标识标签ID-tags2.4 创建对象包含歌词相关信息 3、播放显示歌词** 相关文献 JavaFX: Java音乐播放 1、lrc歌词文件 lrc歌词文件的扩展名 1、标准格式&a…

图像处理:Retinex算法

目录 前言 概念介绍 Retinex算法理论 单尺度Retinex(SSR) 多尺度Retinex(MSR) 多尺度自适应增益Retinex(MSRCR) Opencv实现Retinex算法 SSR算法 MCR算法 MSRCR算法 效果展示 总结 参考文章 前…

基频建模方法总结

基频F0建模方法 语音合成领域需要对基频进行建模,具体到文语转换TTS、语音转换VC、情感语音转换EVC领域等。 语音合成F0 包括文语转换,情感语音转换 TTEF:text-to-emotional-features synthesis EVC:emotional voice conversio…

这些你熟知的 app 和服务,都用上了人工智能

从微软在 Microsoft 365 服务中全面整合 GPT-4 能力 ,让 PPT、Word 文档、Excel 表格的制作变成了「一句话的事」,到 Adobe 刚刚发布 Adobe Firefly模型集合,让图形设计、字体风格、视频渲染乃至 3D 建模的门槛显著降低——你我熟知的那些工…

idea的快捷键

一.idea的快捷键: 递进选择&#xff1a;ctrl w复制行&#xff1a;ctrl d删除行&#xff1a;ctrl y大小写切换&#xff1a;ctrl shift u展开/折叠&#xff1a;ctrl shift 减号/加号向前/向后&#xff1a;ctrl <— / —>Live Template(例如 输入psvm会自动打出mai…

华为OD机试题,用 Java 解【最远足迹】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不要…

Python实战项目:手势识别控制电脑音量

今天给大家带来一个OpenCV的实战小项目——手势识别控制电脑音量 先上个效果图&#xff1a; 通过大拇指和食指间的开合距离来调节电脑音量&#xff0c;即通过识别大拇指与食指这两个关键点之间的距离来控制电脑音量大小 技术交流 技术要学会分享、交流&#xff0c;不建议闭…

石英晶体振荡器【Multisim】【高频电子线路】

目录 一、实验目的与要求 二、实验仪器 三、实验内容与测试结果 1、观察输出波形&#xff0c;测量振荡频率和输出电压幅度 2、测量静态工作点的变化范围(IEQmin~IEQmax) 3、测量当静态工作点在上述范围时输出频率和输出电压的变化 4、测量负载变化对振荡频率和输出电压幅…

SpringCloud:微服务保护之初识Sentinel

1.初识Sentinel Sentinel是阿里巴巴开源的一款微服务流量控制组件。Sentinel官网 Sentinel具有以下特征&#xff1a; 丰富的应用场景&#xff1a;Sentinel承接了阿里巴巴近 10 年的双十一大促流量的核心场景&#xff0c;例如秒杀&#xff08;即突发流量控制在系统容量可以承受…

JavaEE阶段测试复习

文章全部内容在个人站点内的置顶文章中,访问密码:AIIT 小凯的宝库 模块三、面向对象 继承: a. 单继承:Java只支持单继承,即一个子类只能有一个直接父类。但子类可以间接地继承多个父类。 b. 构造方法与继承:在子类中可以通过super()关键字调用父类的构造方法。如果子类没…

探索深度学习中的计算图:PyTorch的动态图解析

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Windows系统的JDK安装与配置

1 选择JDK版本 以在Windows 64位平台上安装JDK 8版本为例。JDK 8 Windows版官网下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java8-windows 现在下载需要先注册并登录Oracle的账号。 2 安装 双击jdk安装包&#xff0c;进入安装程序页面直接选择…

freetype用法

freetype用法 文章目录 freetype用法0.实现1.变量定义2.lcd操作获取屏幕信息3.freetype初始化4.绘画 1.字形度量2.类1.FT 中的面向对象2.FT_Library 类3.FT_Face 类4 FT_Size 类5 FT_GlyphSlot 类 3.函数1.把一个字符码转换为一个字形索引FT_Get_Char_Index函数2.从 face 中装…

银行家算法--申请资源

银行家算法–申请资源 问题描述&#xff1a; 输入N个进程(N<100)&#xff0c;以及M类资源&#xff08;M<100&#xff09;&#xff0c;初始化各种资源的总数&#xff0c;T0时刻资源的分配情况。例如&#xff1a; 假定系统中有5个进程{P0&#xff0c;P1&#xff0c;P2&…

文字的显示

文字的显示 文章目录 文字的显示1.文字编码方式2.英文和汉字的点阵显示3.显示中文“中”和“A”show_font.c结果 1.文字编码方式 数字>代表什么->显示为什么 GBK国标拓展 下列代码用不同编码方式保存utf-8.c ansi.c #include <stdio.h>int main(int argc ,char *…