开始时飞船离月球表面有一定距离。月球的重力开始把它向下拉,我们必须使用推进器让它的降落放慢,使它平缓着陆。
这个程序看上去是像右图这样的。
左边的小灰条是推进器。用鼠标上下拖动可以控制发动机的推力。燃料表指出你还剩下多少燃料,上面的文本给出了速度、加速度、高度和推力的有关信息。
模拟着陆
为了模拟飞船着陆,必须理解重力和飞船发动机作用力相互之间如何平衡。
在这个仿真中,我们假设重力是恒定的。事实上并不是这样,不过只要飞船离月球不太远,重力几乎是恒定的(对我们的仿真来说非常接近恒定了)。
术语箱
速度(velocity)与速率“speed”含义几乎是一样的,不过速度还包括方向,而速率不包括方向。例如,“每小时 50 公里”描述的是速率,而“每小时向北 50 公里”描述的就是速度。很多人可能会使用“速率”,但实际上他们所指的是“速度”,反之亦然,有些人谈到“速度”时所指的其实是“速率”。在我们的程序中,我们需要知道飞船是向上还是向下,所以会使用速度。
加速度(acceleration)是指速度变化得多快。正的加速度表示速度在增加,负加速度表示速度在减少。
发动机的作用力取决于燃烧了多少燃料。有时这个作用力会大于重力,有时可能比重力小。发动机关闭时,作用力就为 0,此时只剩下重力。
要得到对飞船的总作用力或净作用力,只需把两个作用力相加。因为它们的方向相反,所以一个为正,另一个为负。
一旦得到飞船上的净作用力,可以利用一个公式得出它的速度和位置。
我们的仿真必须跟踪以下几点。
飞船距离月球的高度,以及飞船的速度和加速度。
飞船的质量(随着燃料的消耗,质量会变化)。
发动机的推力或作用力。使用的推力越大,燃料燃烧得就越快。
飞船上有多少燃料。推进器燃烧燃料时,飞船会变轻,但是如果所有燃料都耗光,就不再有推力。
飞船上的重力。这取决于月球的大小,以及飞船和燃料的质量。
又是 Pygame
我们还是使用 Pygame 建立这个仿真。这里将用 Pygame 的时钟滴答作为我们的时间单位。对于每一个滴答,我们会检查对飞船的净作用力,并更新高度、速度、加速度和剩余的燃料。然后使用这个信息更新图片和文本。
由于动画非常简单,这里不打算用一个动画精灵表示飞船。不过我们会对推进器使用一个精灵(灰色矩形),因为这样就能很容易地用鼠标拖动。燃料表是用 Pygame 的 draw.rect 方法画的两个矩形。文本用 pygame.font 对象建立,就像前面 PyPong 中的做法一样。
代码要完成以下工作。
初始化游戏——建立 Pygame 窗口、加载图像,为变量设置一些初始值。
为推进器定义精灵类。
计算高度、速度、加速度和燃料消耗。
显示这个信息。
更新燃料表。
显示火箭尾焰(取决于推力,尾焰大小会改变)。
把所有内容“块移”(blit)到屏幕,检查鼠标事件,更新推进器位置,并检查飞船是否已经着陆——这就是主 Pygame 事件循环。
显示“游戏结束”和最终统计信息。
代码清单 24-1 显示了 Lunar Lander 的代码,相应的文件是 Listing_24-1.py,可以在 examplesLunarLander 文件夹找到这个文件,或者也可以在网站(www.helloworldbook.com)上找到。在文件夹和网站上还可以找到相关的图片(飞船和月 球)。查看代码和说明,一定要确保你能理解所有内容。先不用担心高度、速度和 加速度的公式。在高中物理中将会学到这些知识,不过考完试后可能很快就会忘掉(除非你在美国航空航天局工作)。也许这个程序能帮你记住这些公式!
代码清单 24-1 Lunar Lander
试着运行这个程序。没准你会发现自己是一个不错的飞船驾驶员!如果你认为这太简单了,可以修改代码,让重力更大一些,使飞船更重(质量更大),或者减少一些燃料,还可以设置一个不同的起始高度或速度。你是程序员,所以游戏该怎么做由你来决定。
Lunar Lander 仿真主要考虑重力。在本章后面的内容,我们将讨论仿真中另一个重要的因素——时间。我们会建立一个需要跟踪时间的仿真。