记于2020.5.27凌晨第二次写完外星人大战小游戏项目,不想说什么,只想说好好努力吧。
1.为了让主函数里面更简洁,所以主函数里面基本上只有一些执行函数,函数的具体实现代码放在其它的模块中。
2.导入模块pygame:模块包含开发游戏所需的功能
导入模块sys: 用sys.exit()退出程序
3.主函数run_game()
(1)pygame.init() 初始化背景设置
(2)pygame.display.set_mode () 设置屏幕
(3)pygame.display.set_caption() 设置标题
(4)创建飞船 (导入飞船这个类,然后创建一个飞船实例,子弹外星人也一样)
(5)创建子弹 (子弹与飞船都用精灵组存储,便于管理)
(6)创建外星人群
(7)创建得分信息(最高分以及目前得分)
(8)创建按钮(开始游戏的按钮)
(9)设置类(设置屏幕,飞船,外星人,子弹的等属性)
4.设置屏幕
(1)更新屏幕 update_screen()
(2)a.更新屏幕上的图像,并切换到新屏幕
b.每次循坏时都重绘屏屏幕
c.用背景色填充屏幕,这个方法只接受一个实参,一种颜色
screen.fill(ai_settings.bg_color)
d.对编组调用draw()时,Pygame自动绘制编组的每个元素,绘制位置由元素的属性rect决定
aliens.draw(screen)
(3)让最近绘制的屏幕可见
pygame.display.flip()
5.设置飞船
(1)图片加载
a.加载位图(python默认加载位图)
在pygame中可以使用pygame.image.load()函数来加载位图。(支持jpg,png,gif,bmp,pcx,tif,tga等多种图片格式)
b.绘制位图
Surface对象有一个名为blit()的方法,它可以绘制位图
screen.blit(space, (0,0)) 第一个参数是加载完成的位图,第二个参数是绘制的起始坐标。
c.绘制飞船到屏幕上
调用方法ship.blitme() 将飞船绘制到屏幕上,确保它出现在背景前面
(2)创建ship类
__init__() 初始化函数
self.screen=screen 初始化飞船并设置其初始位置
self.image=pygame.image.load('images/ship.bmp') 加载飞船图像并获取其外接矩形
self.rect=self.image.get_rect() 获取图片外接矩形
self.screen_rect=screen.get_rect() 获取屏幕外接矩形
将每艘新飞船放在屏幕底部中央
self.rect.centerx=self.screen_rect.centerx 飞船中心x坐标
self.rect.bottom=self.screen_rect.bottom 飞船下边缘y坐标
blitme() 在指定位置绘制飞船
(3) 重构:模块game_functions (简化代码,使程序结构更清晰)
a.函数check_events() (管理事件,用于响应鼠标和键盘按键)
b.函数update_screen() (用于更新模块)
6.驾驶飞船
每当用户按键时,都将在Pygame中注册一个事件。事件都是通过pygame.event.get() 获取的,因此在函数check_events()
中,我们需要指定要检查哪些类型的事 件。每次按键都被注册为一个KEYDOWN 事件。
(1)响应按键(if以及elif)
if event.key == pygame.K_RIGHT
检测KEYDOWN事件,如果是右箭头键,就将ship.rect.centerx 的值加1
(2)允许不断移动
我们添加了一个新的elif 代码块,用于响应KEYUP 事件:玩家松开右箭头键(K_RIGHT )时,我们将moving_right 设置为
False 。
(3)左右移动(与响应按键中一样的,改为按住左键的时候向左移动就行了)
(4)调整飞船的速度(在settings中添加一个设置飞船速度的属性)
(5)限制飞船的活动范围(设置两个if语句)
if self.moving_right and self.rect.right < self.screen_rect.right
if self.moving_left and self.rect.left > 0
(6)重构check_events()
a.响应按键
b.响应松开
c.响应按键和鼠标事件(emm.移代码就行啦)
7.射击
(1)添加子弹设置
在settings中__init__()设置子弹的速度,高度,宽度,颜色
(2)创建Bullet类
from pygame.sprite import Sprite (导入精灵组)
a.创建一个表示子弹的矩形,并设置其正确的位置(设置为飞船的centerx和top属性),然后存储用小数表示的子弹位置
b.把子弹的坐标设置为小数值,以便能够微调子弹的速度
c.在屏幕上绘制子弹
pygame.draw.rect(self.screen, self.color, self.rect)
(3)将子弹存储到编组中
当你对编组调用update() 时,编组将自动对其中的每个精灵调用update() ,因此代码行bullets.update() 将为编组bullets 中的
每颗子弹调用bullet.update()
(4)开火
如果按下的是空格键,则创建一颗子弹将其加入到编组中。
bullets.add(new_bullet)
还要调用update_screen(),然后添加在外星人后面重绘所有子弹这一项功能。
(5)删除已经消失的子弹
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
(6)限制子弹数量
设置一个self.bullets_allowed = 3,保证未消失的子弹限制为三颗。然后在check_keydown_events()中,还要用一个if语句,检查屏幕上的子弹是否小于三颗。
(7)创建函数update_bullets()
把alien_invasion.py中的主函数中的删除已经消失的子弹那一部分代码重新移到这个新创建的函数中。
(8)创建函数fire_bullet()
把发射子弹的那一部分代码移到这个新创建的函数中去,使程序更简单明了。
8.创建第一个外星人
(1)创建alien类
创建一个alien.py模块,导入精灵组这个模块,外星人也用精灵组存储。
a.初始化外星人并设置其起始位置
b.加载外星人图像,并设置其rect属性
c.每个外星人最初都在屏幕左上角附近
d.存储外星人的准确位置(用浮点数存储)
e.在指定位置绘制外星人
(2)创建alien实例
在run_game()中创建第一个外星人,并且在更新屏幕的函数中将外星人这个参数传过去。
(3)让外星人出现在屏幕上
在update_screen()中调用方法blitme()
9.创建一群外星人
(1)确定一行可容纳多少个外星人
available_space_x = ai_settings.screen_width – (2 * alien_width)
number_aliens_x = available_space_x / (2 * alien_width)
(2)创建多行外星人
a.在alien_invasion.py中创建一个名为aliens 的空编组
b.在update_screen()中传递aliens
(3)创建外星人群
a.创建一个新函数create_fleet(),然后用一个for循环创建第一行外星人。
b.使用了int() 来确保计算得到的外星人数量为整数
(4)重构create_fleet()
将计算每行可容纳多少个外星人的代码移出来,新创建一个函数get_number_aliens_x()
(5)添加行
a.计算屏幕上可容纳多少行外星人
available_space_y = ai_settings.screen_height – 3 * alien_height – ship_height
number_rows = available_height_y / (2 * alien_height)
b.用for循坏,创建一行行外星人
10.让外星人群移动
(1)向右移动外星人
a.外星人向右移动
self.x += self.ai_settings.alien_speed_factor
self.rect.x = self.x
b.更新外星人群中所有外星人的位置
aliens.update()
(2)创建表示外星人移动方向的设置
a.fleet_direction为1表示向右移,为-1表示向左移
b.设置fleet_drop_speed 指定了有外星人撞到屏幕边缘时,外星人群向下移动的速度。
(3)检查外星人是否撞到了屏幕边缘
用if以及elif语句检测
(4)向下移动外星人群并改变移动方向
a.函数check_fleet_edges() 检测是否到达了屏幕边缘
b.change_fleet_direction() 改变移动方向
11.射杀外星人
(1)检测子弹与外星人的碰
a.精灵组之间的矩形冲突检测
pygame.sprite.groupcollide() 利用这个函数可以检测两个组之间的冲突,他返回一个字典。(键-值对)
b.要模拟能够穿行到屏幕顶端的高能子弹——消灭它击中的每个外星人,可将第一个布尔实参设置 为False ,并让第二个布尔实
参为True 。这样被击中的外星人将消失,但所有的子弹都始终有效,直到抵达屏幕顶端后消失。
(2)为测试创建大子弹
将子弹宽度设置较大,进行测试
(3)生成新的外星人群
a.我们检查编组aliens 是否为空。如果是,就使用方法empty() 删除编组中余下的所有精灵,从而删除现有的所有子弹。调用了create_fleet() ,再次在屏幕上显示一群外星人。
(4)提高子弹的速度
增大bullet_speed_factor 的值
(5)重构update_bullets()
创建了一个新函数——check_bullet_alien_collisions() ,以检测子弹和外星人之间的碰撞,以及在整群外星人都被消灭干净时
采取相应的措施。避免 了update_bullets() 太长,简化了后续的开发工作。
12.结束游戏
(1)检测外星人和飞船之间的碰撞
pygame.sprite.spritecollideany(ship, aliens):
spritecollideany() 接受两个实参:一个精灵和一个编组。它检查编组是否有成员与精灵发生了碰撞,并在找到与精灵发生了碰撞
的成员后就停止遍历编组。在这里, 它遍历编组aliens ,并返回它找到的第一个与飞船发生了碰撞的外星人。
(2)响应外星人和飞船碰撞
a.编写一个用于跟踪游戏统计信息的新类——GameStats
初始化统计信息以及在游戏运行期间可能变化的统计信息
b.在settings中增加一个ship_limit,并将其赋值为3
c.在alien_invasion.py做些修改,创建一个GameStats 实例
d.函数ship_hit()
将ships_left减1,清空外星人列表和子弹列表 ,创建一群新的外星人,并将飞船放到屏幕底端中央 。
(3)有外星人到达屏幕底端
创建一个新函数,并将其命名为update_aliens()
函数check_aliens_bottom() 检查是否有外星人到达了屏幕底端。到达屏幕底端后,外星人的属性rect.bottom 的值大于或等于
屏幕的属性rect.bottom 的值。如果有外星人到达屏幕底端,就调用ship_hit() ;只要检测到一个外星人到达屏幕
底端,就无需检查其他外星人,因此我们在调用ship_hit() 后退出循环。
(4)游戏结束
在ship_hit() 中添加代码,在玩家的飞船都用完后将game_active 设置为False 。
13.确定应运行游戏的哪些部分
在主循环中,在任何情况下都需要调用check_events() ,即便游戏处于非活动状态时亦如此。例如,我们需要知道玩家是否按了
Q键以退出游戏,或单击关闭窗口的按钮。 我们还需要不断更新屏幕,以便在等待玩家是否选择开始新游戏时能够修改屏幕。其
他的函数仅在游戏处于活动状态时才需要调用,因为游戏处于非活动状态时,我们不用更新游戏元素的位置。
14.记分
添加Play按钮
(1)创建Button类
a.我们导入了模块pygame.font ,它让Pygame能够将文本渲染到屏幕上。
b.方法__init__() 接受参数self ,对象ai_settings 和screen ,以及msg ,其中msg 是 要在按钮中显示的文本。
c.设置按钮的尺寸,然后通过设置button_color 让按钮的rect 对象为亮绿色,并通过设置text_color 让文本为白色。
d.self.font = pygame.font.SysFont(None, 48) 实参None让Pygame使用默认字体。
e.Pygame通过将你要显示的字符串渲染为图像来处理文本,我们调用prep_msg() 来处理这样的渲染。
(2)在屏幕上绘制按钮
a.在alien_invasion.py中导入Button类,创建一个实例
b.然后我们将play_button 传递给update_screen() ,以便能够在屏幕更新时显示按钮
c.修改update_screen() ,以便在游戏处于非活动状态时显示Play按钮
d.为让Play按钮位于其他所有屏幕元素上面,我们在绘制其他所有游戏元素后再绘制这个按钮,然后切换到新屏幕。
(3)开始游戏
a.我们修改了check_events() 的定义,在其中添加了形参stats 和play_button 。我们将使用stats 来访问标志game_active ,并
使用play_button 来检查玩家是否单击了Play按钮。
b.我们使用 了pygame.mouse.get_pos() ,它返回一个元组,其中包含玩家单击时鼠标的x和y坐标。
c.用collidepoint() 检查鼠标单击位置是否在Play按钮的rect内
(4)重置游戏
在玩家每次单击Play按钮时都重置游戏,需要重置统计信息、删除现有的外星人和子弹、创建一群新的外星人,并让飞船居中.
(5)将Play按钮切换到非活动状态
标志button_clicked 的值为True 或False,仅当玩家单击了Play按钮且游戏当前处于非活动状态时,游戏才重新开始。
(6)隐藏光标
pygame.mouse.set_visible(False)
通过向set_visible() 传递False ,让Pygame在光标位于游戏窗口内时将其隐藏起来。游戏结束后,我们将重新显示光标,让玩家
能够单击Play按钮来开始新游戏。
15.提高等级
(1)修改速度设置
a.设置speedup_scale ,用于控制游戏节奏的加快速度
b.使用increase_speed() 来提高飞船、子弹和外星人的速度
每个速度设置都乘以speedup_scale 的值
(2)重置速度
开始新游戏时,都需要将发生了变化的设置重置为初始值。
16.记分
(1)显示得分
a.创建一个新类Scoreboard
b.Scoreboard 在屏幕上显示文本,因此我们首先导入模块pygame.font
c.创建方法show_score() ,用于显示渲染好的得分图像
(2)创建记分牌
a.创建一个Scoreboard 实例
b.将该参数传递给update_screen()
(3)在外星人被消灭时更新得分
a.指定玩家每击落一个外星人都将得到多少个点
b.更新得分和记分牌
(4)将消失的每个外星人的点数都计入得分
如果字典collisions 存在,我们就遍历其中的所有值。每个值都是一个列表,包含被同一颗子弹击中的所有外星人。
(5)提高点数
a.定义了点数提高的速度,并称之为score_scale
b.为让点数为整数,使用函数int()
(6)将得分圆整
函数round() 通常让小数精确到小数点后多少位,其中小数位数是由第二个实参指定的。然而,如果将第二个实参指定为负数,
round() 将圆整到最近的10、100、1000等整数倍。
(7)最高得分
a.在任何情况下都不会重置最高得分,在__init__() 中而不是reset_stats() 中初始化high_score 。
b.新方法prep_high_score() ,用于准备包含最高得分的图像。
c.为检查是否诞生了新的最高得分,在game_functions.py中添加一个新函数check_high_score() 。
(8)显示等级
a.确保每次开始新游戏时都重置等级,在reset_stats() 中初始化它
b.让Scoreboard 能够在当前得分下方显示当前等级,在__init__() 中调用了一个新方法prep_level()
c.如果整群外星人都被消灭,就提高一个等级
(9)显示余下的飞船数
a.首先,需要让Ship继承Sprite ,以便能够创建飞船编组
b.为在屏幕上显示飞船,对编组调用了draw()
c.为在游戏开始时让玩家知道他有多少艘飞船,在开始新游戏时调用prep_ships()
d.飞船被外星人撞到时调用prep_ships() ,从而在玩家损失一艘飞船时更新飞船图像