导航菜单
首页 » 分享 » 正文

通杀爆改 Unity FPS 游戏系列(第四章) 子弹范围子弹追踪

索引

通杀爆改 Unity FPS 游戏系列-序章

通杀爆改 Unity FPS 游戏系列-第一章

通杀爆改 Unity FPS 游戏系列-第二章

通杀爆改 Unity FPS 游戏系列-第三章

本章内容效果展示子弹命中的判定机制Unity 提供的物理碰撞检测分析子弹范围实现子弹范围效果展示

子弹命中的判定机制

目前子弹的判定机制有 3 种

直译为命中扫描

可以简单地理解为:命中的结果是扫描出来的,而非实际命中碰撞得到的

这里的扫描:在发射的位置打出一条射线,通过射线来判断是否命中

如下图所示,从枪口发射出了一条射线,这条射线途径的物体会被判定为命中

根据 的特性,可以推断出:在开枪(发出射线)的那一刻,命中结果就已经确定了

但这也会存在一个问题:损失了真实性,无法通过重力,风力等其他外部因素来影响命中的轨迹

同时假设一个敌人在很远的距离,理论上子弹需要飞行一段时间才会命中,这段时间内敌人是有机会躲避的

但是如果只是采用 进行判定,在开枪的那一刻结果就已经注定了

弹射

子弹是真实存在的物理对象,可以设定子弹的速度、重力 等一系列影响子弹运行轨迹的参数

只有当子弹真正 "运动" 到了对应的位置,才会判定为命中

拿个最简单的对比图:

左图为

右图为

前面提到的 和 各有其优缺点

轨迹性能真实性子弹

直线

计算简单

射线替代

曲线

相对复杂

真实生成

而 就是共同使用 和

在 的基础上加上

以最高点为例子:

红线表示子弹在 "真实运动" 到最高点时发出的 射线

如果红线命中了物体,则判定子弹击中了物体

可以简单地做如下理解:

是在子弹发射点(一般为枪口) 发出一条较长的射线,命中结果在开枪的这一刻就已经决定了

则是模拟子弹真实运动,子弹的运动轨迹受重力和风速等参数影响,命中结果得在运动过程中实际碰到物体才行

则是在 的基础上额外加上了 的命中判定,不过此时的射线对比 就短得多

轨迹性能真实性子弹应用场景

直线

计算简单

射线替代

狙击枪发射的子弹(飞行速度极快)

曲线

相对复杂

真实生成

普通的子弹,比如霰弹枪,下坠很大

曲线

结合

真实生成 + 射线替代

相对自由

Unity 提供的物理碰撞检测碰撞体

首先明确一点,物理碰撞检测的对象是碰撞体

碰撞体可以简单的理解为 不可见 的用于物理碰撞的游戏对象的形状,通常采用粗略近似而非完全贴合游戏对象(节省性能)

如上图所示,绿色边框为一个 (球形碰撞体),可以看到并没有和敌人完全贴合,而是粗略近似的覆盖

常用的碰撞体有:为盒型碰撞体、球形碰撞体和胶囊碰撞体,限于篇幅不展开介绍,简单的区别就是形状不同

而较复杂的碰撞体:(网格碰撞体) 虽然更精准和真实但受限于性能开销,一般较少使用

射线检测

在前面提到的 中,以一个点作为命中判定的起点,然后由该点沿着某个方向发出一条射线,得到这条射线途径的碰撞体

点射线

常用(这里只列举了一个)对应的 Unity 函数为:

    public static int RaycastNonAlloc(Vector3 origin, Vector3 direction, RaycastHit[] results, [UnityEngine.Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [UnityEngine.Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [UnityEngine.Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction)
    {
        return defaultPhysicsScene.Raycast(origin, direction, results, maxDistance, layerMask, queryTriggerInteraction);
    }

参数说明

射线的起点

射线的方向

命中结果

允许射线命中距射线起点的最大距离

用于在投射射线时选择性地忽略碰撞器

ion

指定此查询是否应命中触发器

返回值:命中结果的数量

这里会注意到一个不太 "真实" 的地方,那就是忽略了子弹的体积,直接把子弹看作了一个点,好处显而易见,节省性能

当然在大多数情况下,由于被命中的碰撞体和子弹体积相差较大,因此将子弹看作一个点并不会导致体感上的不真实

但是当子弹体积相对较大时,比如发射一个光波(镭射激光),这个时候用一个点进行判定显然就不太合适了

除了使用前面提到的 命中判定(给子弹也挂一个碰撞体,当子弹的碰撞体和其它碰撞体实际接触时才判定命中)外

还可以使用球形射线

球形射线

球形射线:对场景中的所有碰撞器投射一个球体并返回每个被击中的碰撞器的详细信息

常用(这里只列举了一个)对应的 Unity 函数为:

    public static RaycastHit[] SphereCastAll(Vector3 origin, float radius, Vector3 direction, [UnityEngine.Internal.DefaultValue("Mathf.Infinity")] float maxDistance, [UnityEngine.Internal.DefaultValue("DefaultRaycastLayers")] int layerMask, [UnityEngine.Internal.DefaultValue("QueryTriggerInteraction.UseGlobal")] QueryTriggerInteraction queryTriggerInteraction)
    {
        float magnitude = direction.magnitude;
        if (magnitude > float.Epsilon)
        {
            Vector3 direction2 = direction / magnitude;
            return Query_SphereCastAll(defaultPhysicsScene, origin, radius, direction2, maxDistance, layerMask, queryTriggerInteraction);
        }
        return new RaycastHit[0];
    }

参数说明

射线的起点

球体的半径

射线的方向

命中结果

允许射线命中距射线起点的最大距离

用于在投射射线时选择性地忽略碰撞器

ion

指定此查询是否应命中触发器

可以发现,相较前面的,多了一个参数也就上球体的半径

球体的运动路径合是一个圆柱体,圆柱体扫过的区域如果包含碰撞体则判定命中

触发器

对于 判定机制,则是使用触发器进行碰撞检测

触发器通常用于检测对象之间的重叠或进入某个区域。它们通过 、 和 等回调函数触发事件

简单理解就是,触发器这一机制将碰撞检测移交给了引擎,当引擎发现有其它碰撞体触发了对象时,会通知给对应事件

特性触发器()射线()

基本概念

用于检测物体进入、停留或离开触发区域。

用于检测射线与物体的碰撞。

实现方式

通过 组件设置为触发器。

通过代码发射射线进行检测。

回调函数

使用 、、。

通过 . 等方法手动处理。

依赖组件

需要 (设置为触发器)和 。

不需要特定组件,但通常与 一起使用。

检测频率

低频,基于物体的物理运动触发。

高频,可在每帧或按需调用。

性能

对于大量动态对象,可能会影响性能。

频繁调用可能导致性能问题,需优化使用。

适用场景

区域检测、进入/退出事件。

精确检测、射击、视线检测。

灵活性

依赖物理引擎的更新周期,较为自动化。

手动控制,灵活性高。

复杂性

实现简单,适合初学者。

评论(0)

二维码