持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情
让事物动起来
在现实世界中,物体以各种不同的方式移动,这取决于它们在做什么,游戏必须近似这些运动才能创建一个令人信服的虚拟
表示法。一些游戏可以逃脱不切实际的运动吃豆人,例如,以恒定的速度直线移动,并且可以在瞬间改变方向,但是如果你在驾驶游戏中将这种运动应用于汽车,它会破坏幻觉。毕竟,在驾驶游戏中,您会期望汽车需要一些时间才能达到全速,并且绝对不能在瞬间转动180度!对于具有真实感的游戏,游戏程序员必须考虑是什么让事情动起来。让我们来看看一个典型的驾驶游戏。无论车辆是自行车,拉力赛车还是半卡车,都有来自发动机的力推动它前进。还有其他力量作用于它。车轮的阻力将根据您驾驶的表面而有所不同,因此车辆在泥泞处的处理方式与在柏油路面上的处理方式不同。当然,还有重力,它不断地将汽车拉向地球(玩家可能不会注意到这一点,直到他试图跳一个
峡谷)!实际上,可能有数百种其他力结合在一起,创造了车辆的运动。
幸运的是,对于我们游戏程序员来说,我们只需要模拟其中的几个力,就可以创造出令人信服的运动错觉。一旦我们的模拟代码被编写出来,我们就可以将其应用于游戏中的许多对象。例如,重力会影响一切(除非游戏设置在太空中),因此我们可以将与重力相关的代码应用于任何物体,无论是投掷的手榴弹,从悬崖上掉下来的坦克,还是在空中飞行的斧头。
本章介绍如何以可预测的方式在屏幕上移动对象,以及如何使该移动在其他人的计算机上保持一致。
了解帧速率
关于电脑游戏中的运动,我们需要知道的第一件事是,没有什么是真正移动的——至少在任何物理意义上都不是。计算机屏幕或电视机向我们呈现一系列图像,当图像之间的时间足够短时,我们的大脑会混合图像以产生流体运动的错觉,就像翻书一样。产生平滑运动所需的图像或帧数可能因人而异。电影使用每秒24帧,但电脑游戏往往需要更快的帧速率。每秒三十帧是一个不错的目标速率,但通常
说到帧速率越高,运动看起来就越平滑 - 尽管在每秒约70帧之后,很少有人能检测到任何改善,即使他们声称他们可以!
游戏的帧速率还受显示设备(如监视器)每秒可以刷新的次数的限制。例如,我的LCD显示器的刷新率为60赫兹,这意味着它每秒刷新显示器60次。生成帧的速度快于刷新率可能导致所谓的“撕裂”,即下一帧的一部分与前一帧组合。
获得良好的帧速率通常意味着影响视觉效果,因为计算机所做的工作越多,帧速率就越慢。好消息是,桌面上的计算机可能足够快,可以生成所需的视觉效果。
直线移动
让我们从简单的直线运动开始。 如果我们每帧以固定的量移动图像,那么它看起来会移动。 要水平移动它,我们将添加到x坐标,并且垂直移动它将添加到y坐标中。 清单 5-1 演示了如何水平移动图像。 它在指定的 x 坐标处绘制图像,然后将值 10.0 添加到每一帧,以便在下一帧上向右移动一点。 当 x 坐标经过屏幕的右边缘时,它会设置回 0,这样它就不会完全消失。 移动的 2D 图像通常称为精灵。
如果运行清单 5-1,您将看到河豚图像从左向右滑动。这正是我们一直在寻找的效果,但是清单 5-1 的设计中存在一个缺陷,问题是我们无法确切地知道将图像绘制到屏幕上需要多长时间。它看起来相当平滑,因为我们正在创建一个非常简单的帧,但是在游戏中,绘制帧的时间将根据屏幕上的活动量而变化。我们不想要一款游戏在变得有趣时放慢速度。另一个问题是,清单 5-1 中的 sprite 在功能较弱的计算机上移动得更慢,在功能更强大的计算机上移动得更快。
abount time
解决这个问题的诀窍是使运动基于时间。我们需要知道自上一帧以来已经过去了多少时间,以便我们可以相应地在屏幕上放置所有内容。游戏。时间模块包含一个时钟对象,我们可以使用它来跟踪时间。若要创建时钟对象,请调用其构造函数
时间:
一旦你有了一个时钟对象,你应该每帧调用一次它的成员函数 tick,它以毫秒为单位返回自上次调用以来经过的时间(一秒钟内有1000毫秒):
tick 函数还采用最大帧速率的可选参数。如果游戏在桌面上运行,则可能需要设置此参数,以便它不会使用计算机的所有处理能力:
毫秒通常用于对游戏中的事件进行计时,因为处理整数值而不是小数时间可能更容易,并且每秒 1,000 个时钟计时周期通常足以满足大多数游戏任务的准确度。也就是说,在处理诸如速度之类的事情时,我经常喜欢在几秒钟内工作,因为每秒250像素会使 对我来说比每毫秒0.25像素更有意义。从毫秒转换为秒就像除以 1,000 一样简单:
警告 如果您未使用 Python 3+,请确保除以浮点值 1000.0.如果未包含浮点,则结果将向下舍入为最接近的整数!
那么,我们如何利用time_passed秒来移动精灵呢?我们需要做的第一件事是为子画面选择速度。假设我们的子画面以每秒 250 像素的速度移动。在该速度下,sprite 将在 2.56 秒内覆盖 640 像素屏幕的宽度(640 除以 250)。接下来,我们需要计算出精灵在自上一帧以来的短时间内移动了多远,并将该值添加到 x 坐标中。这个数学很简单:只需将精灵的速度乘以time_passed_seconds。清单 5-2 通过添加基于时间的移动来构建清单 5-1,并且将以相同的速度移动子画面,而不管您在运行 sprite 的计算机的速度如何。
如果运行清单 5-3,您将看到两个精灵在屏幕上移动。顶部的一个以每秒30帧的速度移动,或者像您的计算机所允许的那样流畅;另一个通过每五帧仅更新一次来模拟慢速计算机。您应该看到,尽管第二个精灵的移动非常生涩,但它实际上确实以相同的平均速度移动。因此,对于使用基于时间的运动的游戏,较慢的帧速率将导致不太愉快的观看体验,但实际上不会减慢动作。就个人而言,我不想玩一个每秒运行15帧以下的游戏,它可能会变得非常迷失方向!