子弹在视频游戏中如何工作?


64

我在用C#设计视频游戏时遇到了这个问题。

如果我们考虑《战地风云》或《使命召唤》之类的游戏,那么数百枚甚至数千枚子弹会同时飞行。事件是不断触发的,据我所知,这会吸收很多处理能力……或者是吗?我想知道各种游戏开发人员如何管理(2D和3D)项目符号,以及每种方法最有效的方法是什么。

我读了一个问题:如何在视频游戏中模拟子弹?但是从程序设计的角度来看,它没有涉及项目符号的工作方式。

我有几个主意,但每个都有缺点:


我想到的最有效的方法(用于2D游戏):

假设我要创建一个名为Bullet的类,并且用户长时间按住按钮,将每0.01秒创建一个Bullet对象。本项目符号有:

  • 1速度

  • 2从其拍摄的起始位置

  • 3精灵纹理

  • 4命中效果

由于项目符号是其自己的类,因此它可以管理绘图,移动和动作侦听器本身。

在处理器上处理成千上万的实例化实例然后销毁(触发击中效果时)会不会很困难?RAM空间?


3D游戏的有效方法-我的另一个想法是:

可以说我创建了一个武器类。该武器具有多种功能,其中一些功能:

  • 1检测武器瞄准的位置,并确定它是否在瞄准目标

  • 2触发枪声的动画

  • 3有一个doDamage()方法,该方法指示从枪支指向的内容中减去生命值

  • 4按下按钮时通知项目符号动画类

然后,我可以创建一个静态类,例如BulletAnimation,它可以从触发它的枪支所在的位置,该枪支指向的位置(用于子弹目的地)获取通知,以及有关用于子弹的适当精灵和速度的信息。然后,此类根据位置和所需的精灵绘制精灵(在新线程上,可能是idk),以模拟从枪支发射的子弹。


后者似乎更难编写代码,并且要不断地调用静态函数一次执行成千上万的子弹,是否需要大量处理能力?获取开始位置和结束位置的持续更新也很困难。

我的问题是,游戏创作者最有效的方法是什么?这种方法会从2D游戏变为3D游戏吗?


16
请注意,即使在今天,大多数游戏也不模拟子弹的飞行。对于任何被认为“足够快”的事物,将执行简单的点击扫描-基本上,假设撞击是在您按下触发器的同时发生的。无论如何,“数百个或数千个子弹”并不是什么大数目,这是游戏自早期的游戏机(各种子弹地狱游戏)以来所具有的功能,其功能比当今的机器弱数千倍。您只需要确保每个子弹只做尽可能少的工作即可:)
六安'16

42
项目符号通常通过pew-pew-pew技术来运作:)
MonkeyZeus '16

5
永远不会有成千上万的子弹同时飞来飞去。没有枪可以这么快地射击他们。甚至强大的方阵也能以每秒75发子弹的速度登顶。根据Wikipedia上列出的“有效射击距离”,子弹最多飞行约3秒钟,因此方阵可以一次将225枚子弹置于空中。M16的最高发球速度约为12发/秒,无法维持该速度(持续射击的最大速度为0.25发/秒)。一次没有多少枪射击!
Cort Ammon

3
仅指出这一点,当对象如此简单时,使对象成为单独的类永远都不是一件好事。每种项目符号类型最好有一个bulletField实例。代码长度稍有开销,而每个子弹将为您节省额外的4字节字(如果类型是整数)。另外,一个对象可以轻松扫描列表。
伟大的鸭子

4
@Cort-假设游戏空间中只有一支枪支,这是真的。OP提到了《战地风云(Battlefield)》和《 CoD》等游戏,其中数十名玩家可以同时发射自动火炮。如果每个回合实际上是在太空中计算出来的,那么有一个荒谬的数字并不是没有道理的。
杰西·威廉姆斯

Answers:


78

我当然可以理解为什么您会认为很难模拟它们,但是对子弹(实际上是所有射弹)有足够的约束以使其更容易使用。

  1. 通常将它们模拟为单个点,而不是模拟为具有一定体积的东西。这使碰撞检测变得非常容易,因为现在我只需要对非常简单的表面(如直线与圆)进行碰撞。

  2. 我们知道它们将如何移动,因此不需要为它们存储或计算太多信息。您的清单相当准确,我们通常会与之关联一些其他信息,例如谁发了子弹,以及它的类型。

  3. 由于所有弹丸都非常相似,因此我们可以预先分配它们,以避免动态创建它们的所有开销。我可以分配一个包含1000个弹丸的数组,现在可以仅通过一个索引对其进行访问,并且它们在内存中都是顺序的,因此处理它们将很快。

  4. 它们具有固定的生命周期/范围,因此我可以使旧项目符号过期并使内存很快地回收为新项目符号。

  5. 一旦它们撞到某物,我也可以使它们过期,因此它们的寿命有限。

  6. 因为我们知道它们的创建时间,所以如果我们需要新的并且我们在预先分配的列表中没有任何空闲空间,那么我可以抓住最旧的并回收它们,而人们不会注意到子弹是否过早失效。

  7. 它们通常以精灵(sprite)或低多边形模型的形式呈现,并且在屏幕上占用的空间很小,因此可以快速呈现。

考虑到所有这些因素,子弹往往相对便宜。如果我们的预算曾经被子弹消耗并渲染过,我们通常会重新设计它以限制一次可以射击的数量(在许多旧的街机游戏中都会看到),请使用可即时移动的光束武器,或放慢射速,以确保我们不超出预算。


12
我必须不同意5),这实际上会使现代游戏中的整个事情变得复杂。在早期的射击游戏中,这是可以接受的,如今,甚至COD都允许玩家通过木墙射击。6)对于任何竞争系统来说都是不可接受的,尽管这将是一个罕见的问题。
SBoss '16

17
@SBoss然后改写:“一旦它们撞到了无法穿透的东西,我也可以使它们失效,因此它们的寿命有限。” 对于6,您可能会遇到最坏的情况,方法是限制每个角色的最大射击速度,然后保持长度数组num_characters * max_bullets_per_character
棘手怪胎

14
@SBoss我认为#6更适合例如。自上而下的太空游戏,其中缓慢移动的子弹可能会在击中/消失之前在屏幕外移动很长一段距离。显然,在CoD型游戏中,子弹快速移动并迅速到达世界范围并不是问题。
BlueRaja-Danny Pflughoeft

1
绝大多数游戏根本不建模子弹(外部弹道)。大多数游戏采用一种称为“命中扫描”的技术。
阿隆

45

实施项目符号的最有效方法之一可能是使用所谓的hitscan。它的实现非常简单-发射时,您会检查枪瞄准的目标(可能使用射线来找到最接近的实体/物体/网格),然后“击中”它,造成伤害。如果您想使其看起来更像是发射了实际的,快速移动的隐形子弹,则可以通过在损坏之前根据距离增加一点延迟来伪造它。

该方法基本上假定发射的弹丸具有无限的速度,并且通常用于武器类型,例如激光和粒子束/大炮以及某些形式的狙击步枪

下一种方法是将发射的子弹建模为弹丸,将其建模为自身的实体/物体,该实体/物体可能会发生碰撞,并且可能会因重力和/或空气阻力而改变其方向和速度。由于存在额外的物理方程,因此它比Hitscan方法更复杂,并且由于存在实际的子弹对象,因此会占用更多资源,但可以提供更逼真的子弹。

至于管理基于弹丸的子弹与游戏中其他物体之间的碰撞,通过将物体分类为四边形八叉树,可以大大简化碰撞检测。八叉树主要用于3d游戏,而四叉树可以用于2d或3d游戏。使用这些树之一的优点是可以大大减少可能发生的冲突检查的次数。例如,如果在关卡中有20个活动对象,而未使用这些树之一,则必须检查所有20个对象是否与子弹发生碰撞。在树的叶子(末端节点)之间划分20个对象,您可以将检查数量减少到与子弹相同的叶子中存在许多实体。

至于这些方法– Hitscan和Projectile,都可以在2d或3d游戏中自由使用。这更多地取决于武器是什么,以及创作者如何决定武器应发挥作用。


有关设计模式,Hitscan和四叉树/八叉树的信息确实很有帮助。另外,感谢您的信息!
埃里克

8
如果您不起诉HitScan,而是模拟弹丸,那么它们可以穿过薄薄的物体,因为它们移动得非常快。在这种情况下,请记住游戏中的一切都是假的。即使子弹只有几厘米长,您也可以像子弹长一米一样进行碰撞检测。这样,您仍然可以进行不错的子弹掉落和飞行时间模拟,而不必担心子弹在不撞到对象的情况下翘曲:)。
Roy T.

2
在游戏中,子弹(相对于大炮弹)的物理特性会受到重力(子弹掉落),空气阻力等事物的影响吗?(也就是说,除了专业游戏以外,其他游戏的重点是精确目标射击或诸如FPS等。)我不是游戏玩家,但令我感到惊讶的是,(有时甚至)需要这样的保真度。
davidbak '16

3
@davidbak:这在很大程度上取决于典型的游戏内遭遇以及游戏类型所期望的真实感。如果您主要是(只不过是?)近距离格斗,那么确实不需要那种忠诚度。但是,如果存在远程作战的选择(例如,狙击手,或者更像RPG的弓箭手),那么如今影响重力的导弹是可以预料的。如果您将火箭发射器指向上方,您仍然希望火箭着陆并在某处爆炸,不是吗?尽管如此,轨迹并不总是从真实的物理学中计算出来的,只是一个近似值(出于性能原因)
hoffmale

1
@davidbak Battlefield,因为Bad Company 2有子弹掉落。既适合步枪,手枪,坦克炮弹,火箭,也应有尽有。《战地风云3》在Origin上是免费的,您可以检查(IIRC)。当然,《战地风云4》也有这个“功能”。您可以看到的其他游戏是“狙击精英”。2或3是较新的标题。物理在那场比赛中起着重要的作用。
Apache

7

我绝不是专家,但要回答您的问题,是的,您将需要提及其中的许多内容。

对于2D示例,您可以具有子弹的位置和速度。(根据实现子弹的方式,您可能还需要生命周期或最大距离。)通常涉及2(x,y)个值。如果它们是浮点数,则为16个字节。如果您有100个子弹,则只有1600bytes或约1.5k。今天的机器上什么都没有。

接下来,您要提到精灵。您只需要一个精灵即可代表每个项目符号。它的大小取决于您要绘制的位深以及它在屏幕上应显示的大小。甚至以每通道32位全浮点256x256的分辨率进行压缩,对于sprite来说是1MB。(这将非常大!)您将在每个项目符号位置绘制相同的精灵,但不会为该精灵的每个副本占用额外的内存。击中效果类似。

您提到每0.01秒触发一次。那将是您的武器每秒发射100发子弹。即使对于未来派武器来说,也很多!根据这篇维基百科文章

扣动扳机时,发射弹药的速率为循环速率。典型的循环射击速率是:突击步枪为600–900 RPM,某些情况下为1,000-1,100 RPM,冲锋枪和机枪为900-1,200 RPM,机枪为600-1,200 RPM。安装在攻击直升机和其他战斗车辆上的M134小型机枪的射速可达到每秒100发以上(6,000 RPM)。

这样一来,攻击直升机的速度就可以了!

对于您在《战地风云》或《使命召唤》等中提到的大世界,他们可能会计算所有这些子弹位置,但如果行动距离较远,则不会绘制所有子弹位置。否则,直到您接近它们,它们才能模拟它们。(我不得不承认我在这一部分上有一些猜测,因为我还没有做过那么大的事情。)


6

在处理器上处理成千上万的实例化实例然后销毁(触发击中效果时)会不会很困难?RAM空间?

我认为您低估了计算机的速度。这有时在80和90年代的系统的一个问题。这是部分原因,为什么原始的“太空侵略者”要等到当前子弹击中后才让您发射另一枚子弹。如果屏幕上的精灵过多,则某些游戏会遭受“减速”的影响。

如今,是吗?您具有足够的处理能力,可以进行纹理化和照明所需的每个像素数千次操作。数以千计的移动物体没有问题。这使您可以进行可破坏的地形(例如“红色派系”),其中每个片段都会与其他片段进行碰撞处理并遵循弹道曲线。

您需要在算法上稍加小心-当您有成千上万个对象时,您不能天真地将每个对象与其他对象进行检查。项目符号通常不检查是否与其他项目符号冲突。

一个附带的趣闻:网络版《毁灭战士》的第一个版本(原始的90年代)每发射一枚子弹就通过网络发送一个数据包。当一个或多个玩家拿起机枪时,这很容易使网络不堪重负。90年代到处都是人,在大学或工作网络上非法玩《毁灭战士》,当网络变得不可用时,他们的网络管理员就陷入困境。


我想知道电锯在这种情况下是如何工作的
伊利亚·罗克斯

1
IIRC,第一个网络厄运的真正问题在于它避免了使用广播数据包将每个数据包分别发送给每个相对播放器的需要。这减少了发送数据包的数量,但是不幸的是,网络上的每台计算机(包括那些没有玩游戏的计算机)都承受了相当大的CPU负载。
超级猫

1

我距离专家还很远,但是我在业余时间一直在从事多人2D射击游戏。

我的方法

客户端和服务器之间有不同的项目符号类(即使在脱机播放时,服务器实例也是在单独的进程上启动并由“主”游戏连接)。

客户端每隔一刻(每秒60次)就会确定玩家的鼠标指针与屏幕中心(其角色所在的位置)之间的方位,这是发送到服务器的信息的一部分。如果玩家在那一刻也开火(假设武器已经装好并准备就绪),则将创建服务器端子弹实例,其中仅包含一些坐标和基本伤害(这取决于射击武器的统计数据)它)。然后,子弹实例使用一些数学函数来计算我们从客户端收集的方位的X和Y速度。

对于随后的每个滴答声,子弹都会根据这些坐标移动,并将其基础伤害降低预定义的数量。如果此值小于1,或者如果它击中了世界上的一个实心对象,则将删除子弹实例,并且由于测试点碰撞在2D中非常便宜,因此即使快速射击武器对性能的影响也可以忽略不计。

对于客户端,实际上并没有通过网络接收项目符号信息(这在测试中被证明是浪费的),而作为每次更新的一部分,每个字符都有一个“发射”布尔值,如果为true,则客户端会创建一个本地bullet对象几乎和服务器一样工作,唯一的区别是它有一个sprite。

这意味着,尽管您看到的子弹并非在服务器上完全准确地表示出来,但对于玩家而言,任何区别几乎都不会被察觉,而且网络带来的好处超过了任何不一致之处。

注意不同的方法

某些游戏(包括我自己的游戏)会在每个刻度上移动子弹,就好像它们是物理对象一样,而其他游戏则只是沿射击方向创建矢量,或者在所创建的刻度内计算子弹的整个路径,例如在Counter-罢工游戏。客户端可以通过一些小技巧来掩饰它,例如子弹发射的动画,但是从所有意图和目的来看,每颗子弹都不过是激光

对于可能具有复杂命中框的3D模型,标准是针对简单的边界框FIRST测试碰撞,如果成功,则继续进行更多“详细”碰撞检测。


0

这就是所谓的碰撞检测。8位计算机使用硬件中的播放器导弹图形来执行此操作。现代游戏引擎使用物理引擎和线性代数。武器的当前方向表示为3D向量。这就向着火的方向提供了无限的直线。每个运动物体都有一个或多个边界球,因为这是检测与直线碰撞的最简单物体。如果两个相交,那就很成功,否则就没有成功。但是风景可能会妨碍您,因此也必须对其进行检查(使用分层边界体积)。具有相交的最近物体是被击中的物体。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.