You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
9.3 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 第10讲 | 如何载入“飞机”和“敌人”?
上周,我向你解释了如何载入背景图片,以及如何使用坐标值的变换来移动背景图片。今天,我们要载入主角“飞机”和一些“敌人”。
## 导入随机函数
我们选择Python做为开发语言。在开始之前需要用到一个随机函数这个随机函数会在之后的代码中用到具体用作什么我会在后面揭晓。
首先需要将随机函数导入Python的随机函数库random。代码可以这么写
```
import random
```
然后我们需要限定一个范围来生成随机数比如10到100的范围代码可以这么写
```
random.randrange(10, 100)
```
这个函数会接受三个参数:开始、结束、递增数字。
* 开始:开始随机的指定范围数值,包含在范围内。比如(10100)就包含10。
* 结束:开始随机的指定范围数值,不包含在范围内。比如(10100)不包含100最多到99。
* 递增:指定递增数字。
如果不填写递增值,则按照开始、结束的值随机分配。比如 (10100) 那就会在1099之间随机分配任何一个数字。
## 载入主角飞机
我们说完了随机函数的准备工作,就可以开始载入飞机了。
我们假设主角的飞机是从下往上飞,那它的飞机头应该是朝着电脑屏幕上方,而敌人的飞机是从上往下出现,所以它的飞机头应该朝着电脑屏幕的下方。主角的飞机暂时固定在屏幕下方,敌人的飞机则一直不停从上往下飞。
飞机的图片是我从共享的图片网站上抓取下来让美术帮我处理和加工了一下。其实就是将飞机从一整块背景图片上抠除下来让飞机看起来拥有飞机本身的轮廓而不是一幅“方块”的飞机图片然后将其图片保存成png的格式。
我们来看这里的代码。和载入背景一样,我们需要先定义主角飞机的图片名和敌人飞机的图片名。
```
plane = 'plane.png'
enemy = 'enemy.png'
```
使用png格式的原因是png格式包含alpha通道。我们可以将图片抠成透明图这样将图片贴在背景上面就看不到任何黑色块。
我们先尝试贴一下主角的飞机。
```
pln = pygame.image.load(plane).convert_alpha()
screen.blit(pln, (40, 350))
pygame.display.update()
```
我们定义一个叫pln的变量载入plane图片并且将alpha通道进行处理然后在屏幕中绘制pln最后我们使用update函数更新屏幕。
我们来看一下贴图的效果。
![](https://static001.geekbang.org/resource/image/3b/ca/3b13e0a3ff4b7006ee4a1ddbaf8309ca.jpg)
我们已经将这幅图片贴了上去。
在载入的过程中如果我不使用convert\_alpha函数会怎样呢我们也来做一下实验。
```
pln = pygame.image.load(plane).convert()
screen.blit(pln, (40, 350))
pygame.display.update()
```
我将 convert\_alpha 改成了convert来看一下效果。
![](https://static001.geekbang.org/resource/image/4b/57/4ba2eb42b15c44056099e53489104d57.jpg)
看到了那个大大的黑色色块没有这就是我们没有处理alpha通道导致的结果导致了一个大大的抠图色块出现在屏幕所以要记住
1. 设计主角图的时候,要将图片抠下来;
2. 在贴图的时候需要进行alpha混合的处理否则贴上去的图会存在抠图黑块。
## 载入敌人飞机
接下来,我们要从屏幕上方,贴一架敌人的飞机。
```
enm = pygame.image.load(enemy).convert_alpha()
screen.blit(enm, (30, 10))
pygame.display.update()
```
我们将两架飞机前后代码整合起来,再来看一下效果。
![](https://static001.geekbang.org/resource/image/ee/31/ee3059e4cb999d4a5f532c634e88d331.jpg)
这样,我们将两架飞机都贴在了屏幕上了。看起来是不是有点像样了呢?
敌方肯定不止一个飞机,那我们就需要贴更多的敌方飞机。这里我们就需要用到最开始提到的随机函数了。为什么使用随机函数呢?因为我们需要让敌方飞机的排列看起来很随机(笑)。
我们现在要加载相同的敌方飞机图片,加载三次。也就是说,我们会在屏幕上方的一个固定区域范围贴上三次敌人的飞机。我们需要准备三个随机 (xy) 位置的数字,并且赋值给 blit 函数。
```
ex1 = random.randrange(20, 600)
ey1 = random.randrange(10, 50)
ex2 = random.randrange(20, 600)
ey2 = random.randrange(10, 50)
ex3 = random.randrange(20, 600)
ey3 = random.randrange(10, 50)
screen.blit(enm, (ex1, ey1))
screen.blit(enm, (ex2, ey2))
screen.blit(enm, (ex3, ey3))
```
这样,我们就贴上了三幅飞机的图片。
我们再来看一下效果。
![](https://static001.geekbang.org/resource/image/b9/7d/b932a985b390ccf359a4a56f25796c7d.jpg)
是不是看起来很有意思但是这样并不能让飞机动起来我们需要用到上一节里移动背景图片的知识来让敌人的飞机动起来。我们只需要将这三个y值在循环中设置成递增就可以做到三架飞机的移动了。代码就像这样
```
screen.blit(enm, (ex1, ey1))
screen.blit(enm, (ex2, ey2))
screen.blit(enm, (ex3, ey3))
ey1 +=1
ey2 +=1
ey3 +=1
```
这样我们就完成了敌人飞机不停往下飞的效果了。
后面的内容,也会像现在这样,代码很多,我带你再梳理一下逻辑。
**首先我们需要使用Python程序库的随机函数来制作随机数。**
1. 通过这个随机函数,来随机载入敌人飞机的位置。当然如果有游戏策划的话,游戏可能会由某种固定的起始点来刷出敌人飞机,这里我们只用到随机函数来刷敌人飞机。
2. 如果想要做得更漂亮的话我们可以将随机函数的值从屏幕最上方刷出来这样看起来敌人就是从屏幕最上方飞下来的。比如我们可以设置y值为-10左右。
3. 如果想要做得更精细的话我们可以通过程序得到图片的长和宽。通过图片的长和宽来计算刷出飞机的位置我们可以使用屏幕大小来减去飞机长宽的大小来计算比如屏幕长是640图片的长是8。那么我们在设置 x 轴位置的时候就应该最大只设置到640-8这样的位置。这样就不至于我们在编程的时候只刷出半架飞机或者根本就看不到飞机。
**其次,我们在载入敌人飞机的时候,需要贴三幅图片。**
1. 当然我们可以优化这一系列的代码比如我们可以将一系列blit放在一个函数里面。上述的代码只是一个针对教学用的代码为的是让你更直观、明了地能看明白如何载入三幅敌人飞机的图片。我们优化了代码后可以直接使用一段代码和一系列数组就可以完成这个操作。
2. 如果做了一幅alpha通道抠图的图片我们在载入的时候需要处理alpha通道的数据让其图片达到“透明”的效果而不是直接贴一幅有黑框的图片。
**最后,事实上,我们要将这些内容更加完善,还有许多的工作要做。**
1. 这些工作我将在后续的内容中展开讲解。比如我们需要移动背景。这个我们上次已经说明了。在敌人飞机往下飞的过程中,我们需要考虑敌人飞机往下飞的速度,是不是要比屏幕移动的速度更快或者更慢,这样才能体现敌人飞机的等级高低,体现出游戏的难度是随着关卡的变化越来越难的。
2. 我们将游戏背景的图片blit函数放在游戏循环的最开始而载入飞机的代码则放在稍后的部分那么如果我们将游戏背景的图片放到飞机之后载入会发生什么事情呢如果你一直在练习我在文中提供的代码你应该可以知道这个时候飞机的图片都会不见了只能看到游戏背景。这是因为Pygame是按照blit代码的顺序来载入图片的这部分内容我在后面的内容中讲解。
3. 我们可以将载入的图片资源放到一个资源包中或者放在一个目录中这样游戏的目录就不至于看起来乱七八糟而是非常有序的。比如我们可以将所有和主角飞机相关的内容就放在飞机的目录下和敌人相关的就放在敌人的目录下背景和关卡就放在关卡的目录下这样就看起来就整整齐齐。在编写代码的时候从目录的名字不同可以知道载入的是什么内容比如enemy/plane.png
## 小结
好了,这节内容差不多了。我主要和你讲了三个内容:
1. 随机函数使用random.randrange来做输入开始和结束值就能随机出这一个范围的数字;
2. 让飞机移动起来需要将x或者y的值进行加减变化;
3. 处理alpha混合半透明图片需要使用conver\_alpha函数。
最后,给你留一个小思考题吧。
```
while True:
......
ex1 = random.randrange(20, 600)
ey1 = random.randrange(10, 50)
screen.blit(enm, (ex1, ey1))
pygame.display.update()
```
如果我们把这段代码的ex1, ey1变量放在游戏循环中本来在循环外面并且将ex1, ey1填入到敌人飞机的blit函数中会出现什么样的结果呢
欢迎留言说出你的看法。我在下一节的挑战中等你!