本文内容是使用pygame包来开发一款python2D游戏,类似于我们小时候玩的飞机大战,飞船发射子弹biubiubiu~~然后外星人就消灭了,并且每消灭一群外星人后,玩家都将提高一个等级,随着等级提高游戏节奏也会加快。

下面是本文的结构:

* 规划项目
* 安装pygame
* 飞船与外星人的创建
* 外星人与飞船的战争
* 添加记分牌

详细代码可见我的github,以下内容只是大致介绍,篇幅有限只放了部分,细节之处可以阅读书籍《Python编程:从入门到实践》,本文是基于这本书的项目实践章节12-14所写得。
qinliu0901/python​github.com
<https://link.zhihu.com/?target=https%3A//github.com/qinliu0901/python/tree/master/alien_invasion>
1 规划项目


在做一件事情之前,我们都会先想要为什么做,做什么,怎么做,写一个小游戏也是一样,规划好再动手写项目很重要,弄明白游戏预期要实现什么功能,然后针对这些功能去找到解决方法,then
let's start.

在外星人入侵中,我们要实现的功能有:

* 飞船可以左右移动,并用空格键射击;
* 外星人群从左移动到屏幕右端然后下移一定距离,接着往反方向移动;
* 飞船射杀外星人,也就是子弹与外星人碰撞时,子弹与外星人消失,外星人消灭完后又新创建一群;
* 当外星人撞到飞船,玩家就损失一艘飞船,满3次游戏结束;
* 记录得分,最高得分,等级,余下的飞船数。



2 安装pygame


Pygame项目托管在代码分享网站Bitbucket中,访问https://bitbucket.org/pygame/pygame/downloads/可下载相应的pygame包,再使用pip在命令行里安装。




3 飞船与外星人的创建

3.1 主循环的构建

创建一个空的pygame窗口,游戏的基本结构如下:

alien_invasion.py
import sys import pygame def run_game(): # 初始化游戏并创建一个屏幕对象 pygame.init() screen
= pygame.display.set_mode((1200, 800)) pygame.display.set_caption("Alien
Invasion") # 开始游戏的主循环 while True: # 监视键盘和鼠标事件 for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit() # 让最近绘制的屏幕可见 pygame.display.flip()
run_game()
3.2 存储所有设置的类

将所有的设置存储到一个类中,命名为Settings。

settings.py
class Settings(): """存储所有设置的类""" def __init__(self): """初始化游戏的静态设置""" # 屏幕设置
self.screen_width = 1200 self.screen_height = 700 self.bg_color = (230, 230,
230) # 飞船的设置 self.ship_limit = 3 # 子弹设置 self.bullet_width = 3
self.bullet_height = 15 self.bullet_color = 60, 60, 60 self.bullets_allowed = 3
# 外星人设置 self.fleet_drop_speed = 10
在alieninvasion.py中导入Settings类,创建settings的实例ai_settings,在主循环中重绘屏幕.

alien_invasion.py
def run_game(): '''初始化游戏并定义一个屏幕对象''' pygame.init() ai_settings = Settings()
screen = pygame.display.set_mode( (ai_settings.screen_width,
ai_settings.screen_height)) pygame.display.set_caption('Alien Invasion')



3.3 飞船Ship类

选择表示飞船的图像,导入到Ship类中,再在alien_invasion.py中写入显示到屏幕的代码段。

ship.py
import pygame from pygame.sprite import Sprite class Ship(Sprite):
"""一个飞船类,方便创建飞船编组""" def __init__(self, ai_settings, screen): """初始化飞船设置初始位置"""
super().__init__() self.screen = screen # 加self的可以供类中所有方法使用 self.ai_settings =
ai_settings # 加载飞船图像并获取外接矩形 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 self.rect.bottom =
self.screen_rect.bottom
在alien_invasion.py中导入Ship类,创建飞船的实例,在主循环中重绘屏幕。




3.4 游戏函数


对于飞船的移动,就需要响应按键和鼠标事件,将管理事件的代码放到新函数check_events中,新创建一个game_functions.py用于存储游戏过程中需要用到的函数。由于允许飞船不断移动,所以按键与松开按键需要单独定义。

game_functions.py
def check_keydown_events(event, ai_settings, screen, ship, bullets):
"""响应按键""" if event.key == pygame.K_RIGHT: # 向右移动飞船 ship.moving_right =True
elif event.key == pygame.K_LEFT: # 向左移动飞船 ship.moving_left =True elif event.key
== pygame.K_SPACE: fire_bullet(ai_settings, screen, ship, bullets) elif
event.key == pygame.K_q: sys.exit() def check_keyup_events(event, ship):
"""响应松开""" if event.key == pygame.K_RIGHT: ship.moving_right =False elif
event.key == pygame.K_LEFT: ship.moving_left =False def
check_events(ai_settings, screen, stats, sb, play_button, ship, aliens,
bullets): """响应键盘和鼠标事件""" for event in pygame.event.get(): if event.type ==
pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screen, ship, bullets) elif event.type
== pygame.KEYUP: check_keyup_events(event, ship) elif event.type ==
pygame.MOUSEBUTTONDOWN: mouse_x,mouse_y = pygame.mouse.get_pos()
check_play_button(ai_settings, screen, stats, sb, play_button, ship, aliens,
bullets, mouse_x, mouse_y)
接着在主循环中调用这些函数,及时更新屏幕上的图像。




3.4 子弹bullet类


创建子弹类,将子弹存储到编组Group中,在gamefunctions.py中,加入玩家按空格键时发射子弹。还需修改update_screen(),确保在调用flip()前在屏幕上重绘每颗子弹,删除已消失的子弹(在屏幕外面的)。

bullet.py
class Bullet(Sprite): """飞船发射的子弹的类""" def __init__(self, ai_settings, screen,
ship): """在飞船所处位置创建一个子弹对象""" # 初始化父类Sprite的属性 super().__init__() self.screen =
screen # 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置 self.rect = pygame.Rect(0, 0,
ai_settings.bullet_width, ai_settings.bullet_height) self.rect.centerx =
ship.rect.centerx self.rect.top = ship.rect.top
3.5 外星人Alien类


选择表示外星人的图像,导入到Alien类中,再在alien_invasion.py中创建Alien的实例,写入显示到屏幕的代码段。接着根据计算创建外星人群,把它们放到编组中,并向右向下移动。

alien.py <https://link.zhihu.com/?target=http%3A//alien.py>
import pygame from pygame.sprite import Sprite class Alien(Sprite):
"""一个外星人类""" def __init__(self, ai_settings, screen): """初始化外星人设置初始位置"""
super().__init__() self.screen = screen # 加self的可以供类中所有方法使用 self.ai_settings =
ai_settings # 加载外星人图像并获取外接矩形 self.image = pygame.image.load('images/alien.bmp')
self.rect = self.image.get_rect() # 每个新外星人最初在左上角 self.rect.x = self.rect.width
self.rect.y = self.rect.height # 存储外星人的准确位置 self.x = float(self.rect.x)



4 外星人与飞船的战争

4.1 检测子弹与外星人的碰撞


当子弹击中外星人时,子弹与外星人都消失,方法sprite.groupcollide()将每颗子弹的rect与每个外星人的rect,相比较,返回一个字典,包含发生碰撞的子弹和外星人,每个键时一个子弹,相应的值为被击中的外星人。

game_functions.py
def check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship,
aliens, bullets): # 检查是否有子弹击中了外星人,删除相应子弹外星人,两个true表示删除,两个组之间的 collisions =
pygame.sprite.groupcollide(bullets, aliens, True, True)
4.2 响应外星人和飞船碰撞


当外星人与飞船相撞时,通过跟踪游戏的统计信息来记录飞船被撞了几次,满三次就游戏结束。相对应的编写新类GameStats放入game_stats.py,在alien_invasion.py中创建GameStats的实例。

game_stats.py
class GameStats(): """跟踪游戏的统计信息""" def __init__(self, ai_settings):
"""初始化统计信息""" self.ai_settings = ai_settings self.reset_stats() # 游戏启动时处于非活动状态
self.game_active = False self.hign_score = 0 def reset_stats(self):
"""初始化在游戏运行期间可能变化的统计信息""" self.ships_left = self.ai_settings.ship_limit
self.score = 0 self.level = 1
飞船数量减1,清空外星人与子弹列表,接着创建一群新外星人,将飞船放在屏幕的底部中央。
# 清空外星人列表和子弹列表 aliens.empty() bullets.empty() # 创建一群新外星人,飞船放到屏幕低端中央
create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() sleep(0.5)



5 添加记分牌

5.1 添加play按钮

当玩家点击屏幕中央的play按钮时,开始游戏。创建Button类,实例化按钮,并在屏幕上绘制。

button.py <https://link.zhihu.com/?target=http%3A//button.py>
import pygame.font class Button(): """开始游戏结束游戏的按钮""" def __init__(self,
ai_settings, screen, msg): """初始化按钮属性""" self.screen = screen self.screen_rect
= screen.get_rect() # 设置按钮的尺寸和其它属性 self.width, self.height = 200, 50
self.button_color = (0, 255, 0) self.text_color = (255, 255, 255) self.font =
pygame.font.SysFont(None, 48)



5.2 创建记分牌

为在屏幕上显示得分,创建新类Scoreboard,用来显示当前得分,最高得分,玩家等级,余下的飞船数。

scoreboard.py
class Scoreboard(): """显示得分信息的类""" def __init__(self, ai_settings, screen,
stats): """初始化显示得分信息涉及的属性""" self.screen = screen self.screen_rect =
screen.get_rect() self.ai_settings = ai_settings self.stats = stats #
显示得分信息时的字体设置 self.text_color = (30, 30, 30) self.font =
pygame.font.SysFont(None, 48)
在外星人被消灭时更新得分,更新stats.score的值,再更新得分图像。

检查是否产生了最高得分,显示最高分,并将得分圆整为10的倍数。

scoreboard.py
def prep_hign_score(self): """将最高得分转换为一幅渲染的图像""" #
将得分圆整,为10的倍数,round()让小数精确到小数点后几位 hign_score = int(round(self.stats.hign_score,
-1)) # python3可不要int hign_score_str = "{:,}".format(hign_score)
self.hign_score_img = self.font.render(hign_score_str, True, self.text_color,
self.ai_settings.bg_color)
显示余下的飞船数需要先创建一艘新飞船,再创建一个新编组,每艘飞船左边距为10像素,将剩余的飞船显示在左下角。

scoreboard.py
def prep_ships(self): """显示还剩下多少飞船""" self.ships = Group() for ship_number in
range(self.stats.ships_left): ship = Ship(self.ai_settings, self.screen)
ship.rect.x = 10 + ship_number * ship.rect.width ship.rect.y = 10
self.ships.add(ship)
以上就是大概的思路啦啦啦。


最近总是被一些小事情扰乱心绪,或许是我不够坚定,没能坚持自己的选择吧,有时候就是嫉妒别人怎么那么好,我要是怎样怎样比他还厉害呢,可是我们做了不一样的选择,好像也没法比较了,just
remember:

any choice is a good choice.

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信