外星人入侵笔记

1.开始游戏项目

(1)创建pygame窗口以及相应用户输入
alien_invasion.py:

方法run_game():
初始化游戏并创建一个屏幕对象(pygame.init()、screen、pygame.display.set_caption())

开始游戏主循环(while True):
监视键盘和鼠标事件(event)
让绘制的屏幕可见(pygame.display.flip())
调用方法run_game()

(2)设置背景色
每次循环时都重绘屏幕(bgcolor、screen.fill())

(3)创建设置类Settings
settings.py:
屏幕设置(self.screen_width、self.screen_height、self.bg_color)

为创建Settings实例并使用它来访问设置,对alien_invasion.py进行修改:
初始化pygame,设置和屏幕对象(添加ai_settings,screen)

2.添加飞船图像
游戏中几乎可以使用任何类型的图像文件,但使用位图(.bmp)文件最为简单,因为pygame默认加载位图。
选择图像时,尽可能选择背景透明的图像,这样可使用图像编辑器将其背景设置成任何颜色。

(1)创建Ship类
ship.py:

方法 init():
初始化飞船并设置其初始位置(self.screen)
加载飞船图像并获取其外接矩形(self.image、self.rect、self.screen)
将每艘新飞船放在屏幕底部中央(self.rect.centerx,self.rect.bottom)

方法blitme():
在指定位置绘制飞船(self.screen.blit())

(2)在屏幕上绘制飞船
创建一艘飞船
调用方法ship.blitme()
这时运行,将看到飞船位于空游戏屏幕底部中央

3.重构:模块game_function

(1)函数check_events()
将相应按键和鼠标事件移动至此
在aliens_invasion.py中调用

(2)函数update_screen()
将 更新模块的代码 移动至此
主模块中调用update_screen()

4.驾驶飞船
每当用户按键时,都在pygam中注册一个KEYDOWN事件,事件都是通过方法pygame.event.get()获取的

(1)响应按键
game_fuctions.py:
函数check_event()中,在时间循环中添加elif模块,以便pygame检测到KEYDOWN事件

alien_invasion.py中调用check_events(ship)

(2)允许不断移动
ship.py:
设置移动标志self.moving_right
添加update()方法:
根据移动位置调整飞船位置

game_fuctions.py:
玩家按下右箭头时将moving_right设置为True,并在松开时将其设置为False
添加elif模块,让pygame检测到KEYUP事件
alien_invasion.py的while循环调用ship.update()方法

此时运行alien_invasion.py并按住右箭头键,飞船将不断右移,直至松开为止

(3)左右移动
ship.py:
init()中添加向左移动标志self.moving_left
添加if模块,根据移动标志调整飞船位置

game_fuctions.py:
check_events(ship)中设置响应向左按键和鼠标的事件

此时运行alien_invasion.py,将能够不断地左右移动飞船,如果同时按下左右箭头,飞船将纹丝不动

(4)调整飞船速度
settings.py:
添加飞船的速度属性ship_speed_factor

ship.py:
init()中初始化一个ai_settings的属性
在飞船的属性center中存储小数值,
更新飞船的center值,而不是rect。
根据self.center更新rect对象

alien_invasion.py:
创建Ship实例时,需要传入实参ai_settings、screen

(5)限制飞船的活动范围
ship.py:
对移动标志进行if判断时添加self.rect.right和self.rect.left,即要保证外接矩形的右边缘的x坐标小于屏幕右边缘,左边缘的x坐标要保证大于0

(6)重构check_events()
将check_events()的代码放在两个函数中,一个处理KEYDOWN事件,一个处理KEYUP事件

5.射击
(1)添加子弹设置
settings.py:
init()方法存储新类Bullet所需的值,包括bullet_width,bullet_height,bullet_color,bullet_speed_factor

(2)创建Bullet类
它是一个对飞船发射的子弹进行管理的类,继承了我们从模块pygame.sprite中导入的sprite类,通过使用精灵将游戏中相关的元素编组,进而同时操作编组中的所有元素

bullet.py:
_ init _()方法:
传递ai_settings,screen,ship实例
调用super继承Sprite
创建子弹属性rect
将子弹的centerx设置为飞船的centerx
表示子弹的rect的top属性设置为飞船的rect的top属性,让子弹看起来像是从飞船中射出的
将子弹的y坐标存储为小数值,以便能够微调子弹的速度
将子弹的颜色和速度设置粉笔存储在self.color和self.speed_factor中。

方法update():
向上移动子弹
更新表示子弹位置的小数值
更新表示子弹的rect的位置

方法draw_bullet():
在屏幕上绘制子弹pygame.draw.rect()

(3)将子弹存储到编组中
alien_invasion.py:
创建一个编组,用于存储所有有效的子弹,以便能够管理发射出去的所有子弹
创建一个Group实例,命名为bullets,将其传递给check_events()和update_screen(),并在check_events()后添加bullet.update()

(4)开火
game_functions.py:
修改check_keydown_events():以便在玩家按空格键时发射一颗子弹:
创建一颗子弹,
bullets.add(new_bullet)将其加入到编组bullets中

修改check_events():
再传递一个形参bullets,修改elif模块

修改update_screen():
确保在调用flip()前在屏幕上重绘每颗子弹bullet.draw_bullet()

此时运行,将能够左右移动飞船,并发射任意数量的子弹,子弹在屏幕上向上穿行,抵达屏幕顶部消失

(5)删除已消失的子弹
alien_invasion.py:
当表示子弹的rect的bottom属性为零时,表示子弹已穿过屏幕顶端,bullets.remove(bullet)

(6)限制子弹数量
settings.py:
存储允许的最大子弹数

game_fuctions.py:
check_keydown_events():
在创建新子弹前检查未消失的子弹数len(bullets)是否小于该设置

(7)创建函数update_bullets()
编写并检查子弹管理代码后,可将update_bullets(bullets)移动到game_fuctions.py中,以让主程序文件尽可能简单

(8)创建函数fire_bullet()
将game_fuctions.py中发射子弹的代码移到一个独立的函数fire_bullet()中

在游戏中添加外星人
深入了解pygame和大型项目的管理,学习如何检测游戏对象之间的碰撞,检测碰撞有助于定义游戏元素之间的交互。

1.创建第一个外星人

(1)创建Alien类
alien.py:
方法init():
初始化外星人并设置其起始位置
加载外星人图像,并设置rect属性
每个外星人最初都在屏幕左上角附近(rect.x,rect.y)
存储外星人的准确位置(self.x)

方法blitme():
在指定位置绘制外星人(screen.blit())

(2)创建Alien实例
alien_invasion.py:
创建一个Alien实例,
修改update_screen()的调用,传递一个外星人实例

(3)让外星人出现在屏幕上
game_fuctions.py:
update_screen()中调用方法blitme()

2.创建一群外星人

(1)确定一行可容纳多少个外星人
available_space_x=ai_settings.screen_width-(2*alien_width)
number_aliens_x=available_space_x /(2*alien_width)

(2)创建多行外星人
alien_invasion.py:
创建一个aliens的空编组,用于存储全部外星人
调用create_fleet(ai_settings,screen,aliens)
修改对update_screen()的调用,添加aliens

game_fuctions.py:
对编组调用draw(screen)
pygame自动绘制编组的每个元素,绘制位置由元素的属性rect决定

(3)创建外星人群
game_fuctions.py:
导入Alien类
创建方法create_fleet():
创建一个外星人alien
外星人间距alien_width为外星人的宽度
计算一行可以容纳多少个外星人available_space_x,number_aliens_x
创建第一行外星人(for循环):
创建一个新的外星人,并通过设置x坐标将其加入到当前行

现在运行将会看到第一行外星人

(4)重构creat_fleet()
新建get_number_aliens_x():
计算每行可容纳多少个外星人,返回可容纳的外星人的数量

新建creat_alien():
创建一个外星人并将其放在当前行

creat_fleet():
将计算可用水平空间的代码,替换为对get_number_aliens_x()的调用
for循环中调用creat_alien()

(5)添加行
新建get_number_rows():
计算屏幕可容纳多少行外星人,返回number_rows

creat_alien()中:
修改外星人的y坐标

create_fleet():
新增一个用于存储ship对象的形参
将两个循环嵌套在一起,内部新欢创建一行外星人,外部循环从零数到要创建的外星人的行数

alien_invasion.py:
调用create_fleet()时,需要传递实参ship

现在运行,将看到一群外星人

3.让外星人群移动

(1)向右移动外星人
settings.py:
添加一个控制外星人速度的设置

alien.py:
使用这个设置来实现update()

alien_invasion.py:
更新每个外星人的位置update_aliens(aliens)

game_functions.py:
对编组aliens调用方法update()

(2)创建表示外星人移动方向的标志

settings.py:
添加下移速度属性,左右移动标志

(3)检查外星人是否撞到了屏幕边缘
alien.py:
对任何外星人调用新方法check_edges():
判断外星人是否位于屏幕左边缘或右边缘

修改方法update():
修改移动量

(4)向下移动外星人群并改变移动方向

game_fuctions.py:

check_fleet_edges():
有外星人到达边缘时采取相应的措施

change_fleet_direction():
将整群外星人下移,
并改变它们的方向

update_aliens():
检查是否有外星人位于屏幕边缘
并更新整群外星人的位置

alien_invasion.py:
调用update_aliens()时传递ai_settings对应的实参

现在运行,外星人群在屏幕上来回移动,并在抵达屏幕边缘后向下移动

4.射杀外星人
(1)检测子弹与外星人的碰撞
game_fuctions.py:
update_bullets():
pygame.sprite.groupcollide()将每颗子弹的rect同每个外星人的rect进行比较,并返回一个字典,其中包含发生了碰撞的子弹和外星人。字典中的每个键都是一颗子弹,而相应的值都是被击中的外星人。每当有子弹和外星人的rect重叠时,groupcollide()就在它返回的字典中添加一个键值对。

alien_invasion.py:
调用update_bullets()时,传递实参aliens

此时运行,被击中的外星人将消失

(2)为测试创建大子弹
为了测试效果,可以修改游戏的某些设置,比如屏幕尺寸,子弹速度等

(3)生成新的外星人群
一批外星人被消灭后,出现一批新的外星人

game_functions.py:
检查编组aliens是否为空:
如果是,empty()删除编组中余下的所有精灵,从而删除所有子弹
调用create_fleet(),再次在屏幕上显示一群外星人

alien_invasion.py:
调用update_bullets()

(4)提高子弹的速度
可调整bullet_speed_factor的值

(5)重构update_bullets()
将处理子弹和外星人碰撞的代码移到一个函数中:
check_bullet_alien_collisions()
update_bullets()中调用

5.结束游戏
(1)检测外星人和飞船碰撞
game_functions.py:
pygame.sprite.spritecollideany(sprite,sprite_group)
alien_invasion.py:
将ship传递给update_aliens()

(2)响应外星人和飞船碰撞
game_stats.py:
用来跟踪游戏的统计信息:
初始化统计信息
初始化在游戏运行期间可能变化的统计信息

settings.py:
添加ship_left属性

alien_invasion.py:
导入新类GameStats
创建一个用于存储游戏统计信息的实例stats

game_functions.py:
从模块time中导入sleep()函数

ship_hit()方法:
响应被外星人撞到的飞船
将ship_left减1
清空外星人列表和子弹列表
创建一群新的外星人,并将飞船放到屏幕中央
暂停

update_aliens():
使其包含形参stats、screen和bullets,让它在调用ship_hit()时传递这些值

ship.py:
添加新方法center_ship():
让飞船在屏幕上居中

(3)有外星人到达屏幕底端
game_fuctions.py:
check_aliens_bottom():
检查是否有外星人到达了屏幕底端
若到达,就调用ship_hit(),然后break

update_aliens():
调用check_aliens_bottom()

(4)游戏结束
在GameStats中添加一个座位标志的属性game_active,以便在玩家的飞船用完后结束游戏。

game_stats.py:
设置标识符game_active

game_fuctions.py:
ship_hit():
添加判断语句(检查玩家是否至少还有一艘飞船)
如果是,就创建一群新的外星人,暂停一会,再接着执行
如果不是,就讲game_active设置为False

6.确定应运行游戏的哪些部分

alien_invasion.py:
确定哪些部分仅在游戏处于活动状态时运行,哪些是任何状态下都能运行

此时运行游戏,它将在飞船用完后停止不动

记分
添加一个Play按钮,用于根据需要启动游戏以及在游戏结束后重启游戏。
我们还将修改这个游戏,使其在玩家的等级提高时加快节奏,并实现一个记分系统。

1.添加play按钮

game_stats.py:
设置game_active为False让游戏一开始处于非活动状态

(1)创建button类

button.py:
导入pygame.font模块

init方法:
初始化按钮的属性
设置按钮的尺寸和其他属性
创建按钮的rect对象,并使其居中
按钮的标签纸创建一次(调用方法prep_msg(msg))

方法prep_msg():
接受实参self和要渲染为图像的文本msg
将msg渲染为图像,并使其在按钮上居中:
font.render()将存储在msg中的文本转换为图像,然后将图像存储在msg_image中,还有一个布尔实参,和两个文本颜色和背景色实参

方法draw_button.py:
绘制一个用颜色填充的按钮(screen.fill())
绘制文本(screen.blit())

(2)在屏幕上绘制按钮
alien_invasion.py:
导入button
创建一个名为play_button的实例
将其传递给update_screen()方法

game_fuctions.py:
修改update_screen():
如果游戏处于非活动状态,就绘制play按钮

此时运行,就会在屏幕中央看到一个play按钮

(3)开始游戏

game_fuctions.py:
修改check_events():
添加形参stats和play_button
添加elif模块,判断事件类型是否是MOUSEBUTTONDOWN,若是,使用pygame.mouse.get_pos(),返回一个包含玩家单击时鼠标的x和y坐标的元组,并将这些值传递给函数check_play_button()

check_play_button():
在玩家单击play按钮时开始新游戏:
使用collidepoint()检查鼠标单击位置是否在play按钮的rect内。若是,就将game_active设置为True,让游戏就此开始

alien_invasion.py:
调用check_events()

(4)重置游戏
前面的代码只处理了玩家第一次单击play按钮的情况,没有重置 导致游戏结束的条件

game_fuctions.py:
需要重置统计信息,删除现有的外星人和子弹、创建一群新的外星人

修改check_play_button():
if模块中添加:
重置游戏统计信息
清空外星人列表和子弹列表
创建一群新的外星人,并让飞船居中

game_function.py:
修改check_events():
添加形参aliens
调用check_play_button()修改定义

alien_invasion.py:
调用check_events,传递实参aliens

此时运行,每当玩家单击play按钮时,这个游戏都将正确被重置,想玩几次玩几次

(5)将play按钮切换到非活动状态
当前play按钮存在的问题就是即便play按钮不可见,玩家单击原来所在的区域时,游戏依然会作出响应。

game_fuctions.py:
仅当玩家单击了play按钮且游戏处于非活动状态时,即game_active为False时,游戏才重新开始

(6)隐藏光标
gam_functions.py:

在check_play_button()的if模块中:
添加隐藏光标的语句:
pygame.mouse.set_visible(False)
此时,光标位于游戏窗口内将隐藏起来

ship_hit():
else模块中,在游戏进入非活动状态后,立即让光标可见

2.提高等级

(1)修改速度设置
重新组织settings类,将游戏设置为静态的和动态的两组。

设置speedup_scale,用于控制游戏节奏的加快速度
方法initialize_dynamic_settings():
初试化随游戏而变化的设置:
飞船速度,子弹速度,外星人速度和外星人移动标志。
方法increase_speed(self):
提高速度设置

game_functions.py:
check_bullet_alien_collisions():
在删除现有的子弹后,加快游戏速度(ai_settings.increase_speed()),然后创建一群新的外星人

(2)重置速度
game_functions.py:
check_play_button():
当游戏处于非活动状态时,重置游戏设置(ai_settings.initialize_dynamic_settings())

3.记分
实现一个记分系统,以实时跟进玩家的得分,并显示最高得分、当前等级和余下的飞船数。

在GameStats的reset_stats()中添加一个score属性

(1)显示得分

创建新文件scoreboard.py:
创建一个显示得分信息的类Scoreboard():
init():
初始化显示得分涉及的属性
显示得分信息时使用的字体设置
准备初始得分图像

prep_score(self):
将得分转换为一副渲染的图像
将得分放在屏幕右上角

show_score():
在屏幕上显示得分

(2)创建记分牌
alien_invasion.py中:
导入新建的类Scoreboard
创建一个Scoreboard实例

将sb传递给update_screen():
显示得分:sb.show_score()

(3)在外星人被消灭时更新得分
settings.py:
设置记分点

game_functions.py:
check_bullet_alien_collisions():
每当有外星人被击落时,都更新得分:
if collisions:

update_bullets()中新增形参stats和sb,并更新check_bullet_alien_collisions()的定义

alien_invasion.py中更新update_bullet()的定义

此时运行游戏,得分将不断增加

(4)将消灭的每个外星人的点数都计入得分

当前可能遗漏了一些被消灭的外星人。例如一次循环中有子弹同时击中外星人,玩家只能得到一个被消灭的外星人的点数

因此,调整检测子弹和外星人碰撞的方式
game_fuctions.py:

if collisions:
    for aliens in collisions.values():
    stats.score += ai_settings.alien_points * len(aliens)
    sb.prep_score()

若字典存在,就遍历其中的所有值

(5)提高点数
settings.py:
init():
设置属性表示外星人点数的提高速度
increase_speed():
提高每个外星人的点数

(6)将得分圆整
将得分显示为10的整数倍

(7)最高得分
game_stats.py:
init():
在任何情况下都不应重置最高得分
调用包含最高得分的方法self.prep_high_score()

编写prep_high_score():
将最高得分转换为渲染的图像
将最高得分设置在屏幕顶部中央

方法show_score():
在屏幕上显示最高得分

在game_functions.py中添加一个新函数check_high_score():
检查是否诞生了新的最高得分

game_functions.py:
check_bullet_alien_collisions()中,每当有外星人被消灭后,都需要在更新得分后调用check_high_score()

(8)显示等级
game_stats.py:
reset_stats():
添加一个表示当前等级的属性并初始化

scoreboard.py:
init():
调用新方法prep_level()

新建prep_level():
将等级转换为渲染的图像
将等级放在得分下方

更新show_score():
添加一行在屏幕上显示等级图像的代码

game_functions.py:
check_bullet_alien_collisions():
如果整群外星人都被消灭,就提高一个等级(stats.level加1,并调用prep_level显示新等级)

为确保开始新游戏时更新记分和等级图像,在按钮play被单击时触发重置:
game_functions.py:
check_play_button():
修改定义
重置相关游戏设置后调用prep_score()、prep_high_score()和prep_level()

check_events():
向check_play_button()传递sb

alien_invasion.py:
调用check_events()

(9)显示余下的飞船数
修改ship.py:
让Ship继承Sprite,以便能够创建飞船编组

scoreboard.py:
导入Group和Ship类
init()调用prep_ships()

prep_ships():
显示还余下 多少艘飞船:
创建一个空编组self.ships,用于存储飞船实例

show_score(self):
添加绘制飞船的代码(self.ships.draw(self.screen))

game_functions.py中的check_play_button()调用prep_ships()

update_aliens():
定义添加形参sb
ship_hit()和check_aliens_bottom()都传递了sb

alien_invasion.py中update_aliens()传递sb

你可能感兴趣的:(python)