12.1 规划项目
12.2 安装Pygame
12.3 开始游戏项目
1、创建Pygame窗口以及相应用户输入
首先导入模块sys和pygame
开头函数run_game()函数
pygame.init()初始化背景设置
调用pygame.display.set_mode()创建一个显示窗口,实参(1200,800)是一个元组,指定游戏窗口。
对象screen是一个surface,surface是屏幕的一部分,用于显示游戏元素。每个元素都是surface
while循环控制,其中包含一个事件循环以及管理屏幕更新的代码。
for循环中的事件循环,使用方法pygame.event.get()。所有键盘和鼠标事件都将促使for循环运行。
if语句,如果event.type == pygame.QUIT,执行sys.exit()退出游戏。
pygame.display.flip()让绘制饿屏幕可见。每次执行while循环时都会绘制一个空屏幕,并擦去旧屏幕。在我们移动游戏元素时,该语句将不断更新屏幕。
2、设置背景色
设置背景颜色变量,实参为(255,255,255)之间的数字,区别红,绿,蓝。在while循环外定义。
while循环内调用screen.fill(颜色变量)方法。这个方法只接受一个实参。
3、创建设置类
编写settings的模块,将所有设置储存在一个地方。
12.4 添加飞船图像
使用http://pixabay.com网站提供的素材。
使用位图(.bmp)最为简单,因为Pygame默认加载位图。
使用Pygame方法blit()绘制它。
1、创建ship类
创建ship模块,ship类。
导入模块pygame。Ship类初始方法__init__()接受两个参数:self和screen。后者指定飞船绘制到什么地方。这里的什么地方是指画到哪块画布上。
调用pygame.image.load(图片位置)加载图像。这个函数返回一个surface,储存到self.image中。
使用get_rect()获取相应surface的属性rect。 ---- 就是把图像定义为一个矩形,后续都是操作这个矩形。
处理rect对象时,可使用矩形四角和中心的x和y坐标。可通过设置这些值来指定矩形的位置。
要将元素居中,可设置相应的rect对象的属性center、centerx、centery。要让元素与屏幕边缘对齐,可使用top、bottom、left、right。
定义方法blitme(), ---- self.screen.blit(self.image,self.rect) ---- 在指定位置self.rect加载指定图片self.image.
注意:通过get_rect()将图片实际转换成同等大小的矩形,主要用于位置安排和设置。所以等位置调试完了之后,用self.screen.blit()函数,表示在screen这个surface对象中的图片,其中两个参数是第一个图片参数来覆盖至第二个用来表示位置的矩形参数上,从而显示图片。这个位置参数除了用本节中定义的rect来表示,还可以直接用长宽,xy坐标的元组来直接实现。
2、在屏幕上绘制飞船
在while循环前创建ship类的实例。
在背景填充后,再调用ship.blitme(),确保飞船出现在背景前面。
12.5 重构:模块game_functions
重构即在添加新代码前重构既有代码,为了简化既有代码的结构,使其更容易扩展。本节创建game_functions模块,储存大量游戏运行函数,避免alien_invasion.py太长。
1、函数check_events()
把事件管理的代码移入名为check_events()的函数里。sys导入移入game_functions模块。修改alien_invasion模块,导入该模块,并将循环事件替换为check_events()函数调用。
2、函数update_screen()
新函数update_screen()包含三个形参,其应该对应主程序中的相应变量。形参的设置尽量与主程序和其他两个模块settings.py和ship.py中的函数或类的名称一致,方便调用。但其中的含义要明确,形参就是对应主程序中相应变量。
12.6 驾驶飞船
1、响应按键
每当用户按键时,都将在Pygame中注册一个事件。事件都是通过方法pygame.event.get()获取。
创建一个elif,形成两次条件判断,先判断事件是否为keydown,再判断一次keydown时右键。
2、允许不断移动
直到让游戏检测到pygame.KEYUP事件才停止移动。
在ship模块里加入move_right属性和update()方法。
在game_functions模块里加入调整move_right布尔值的条件判断。
3、左右移动
比照move_right在ship模块和game_functions模块中相应增加属性。
4、调整飞船的速度
在settings模块中增加速度因子的属性。在ship中调用seting模块的相关属性。但是注意,这里导入模块都是在主程序中导入,模块中虽然相互关联,但是不相互导入。比较搞脑筋。
5、限制飞船的活动范围
在update中限制self.rect.right 0则执行坐标一定的update方法。
6、重构check_events()
将keydown和keyup重构为两个函数。
12.7 回顾
12.8 射击
1、添加子弹设置
在settings.py中添加子弹的值,包括子弹速度,宽,高,颜色。
2、创建Bullet类
Bullet类继承了我们从模块pygame.sprite中导入的Sprite类。通过精灵,可将游戏中相关的元素编组。
为创建子弹实例,需要向__init__()传递settings,screen,ship实例,还调用super()来继承Sprite。
创建子弹的属性rect,由于并非基于图像,不能用pygame.image.load加载,要自行设置,调用pygame.Rect(left,top,width,height)创建矩形。即左上角设置xy坐标,设置宽度和高度。
调整子弹的初始位置。centerx调整到飞船的centerx,top调整到飞船的top.
self.rect.y表示子弹的y坐标,调整为浮点型,用于以后微调速度。
方法update()和draw_bullet()
方法update()管理子弹位置,往上移动意味着y坐标变小,先调用浮点型的,在调整为整数型。
方法draw_bullet()绘制子弹。pygame.draw.rect(surface=self.screen,color=self.color,Rect=self.rect,width=0)绘制矩形,也可以用其他句点表达绘制不同形状或者线段。
3&4、将子弹存储到编组中&开火
pygame.sprite.Group类类似于一个列表,创建了一个存储所有有效子弹的编组。
导入Group类,并创建一个实例bullets=Group(),并且这个编组是在while循环之外。
将bullets传递给game_functions.py中,check events处理bullet编组,屏幕更新处理bullet编组。
当对编组调用bullet类中的方法update()时,编组将自动对其中的每个精灵调用update()方法。因此代码bullets.update()将为每个子弹调用bullet.update().
主程序循环逻辑是:当摁下空格键,创建新的子弹实例,存储add进bullets编组,注意编组在while循环外面,所以生成bullet只生成一次,但是主程序循环时,bullets.update()会将里面的bullet实例每一个都-=bullet.speed_factor。每次循环每一个bullet都移动一次,这样会显示每颗不同时候生成的子弹逐步往上走。
在屏幕上绘制子弹的方法update_screen()添加了形参bullets。方法bullets.sprites()返回一个列表,包含编组bullets中的所有精灵。每次循环遍历每个精灵,调用draw_bullet()方法绘制子弹。
5、删除已消失的子弹
在for循环不应该删除编组的条目,因此用.copy()制作副本进行遍历。
在循环中用条件判断bullet的底部
6、限制子弹数量
settings中设置子弹最大数量
game_function中设置条件判断,空格键生成子弹时先判断len(bullets)是否小于最大子弹量。
7、创建函数update_bullets()
把子弹射出到消失整合成函数update_bullets()储存在game_function中,主程序中直接调用。
8、创建函数fire_bullet()
把发射子弹的代码移到独立的函数中。