赞
踩
↑ 关注 + 星标 ,每天学Python新技能
后台回复【大礼包】送你Python自学大礼
这次用Python中的pygame模块来完成一个飞机大战的小游戏;基本思路是通过方向键来控制飞机的左右移动射击飞船。先来看下最后的效果 为了新手也能完成,本文记录了编写的全部流程,也就是每次修改的代码也包括在内,并且给大多数代码都加上了能看懂的注释,看一下最终的的统计字数。 一共敲了4万个字符,希望能帮到感兴趣的读者!
python -m pip --version
小甜是Windows系统,这里只提供Windows系统的检测方法
如果未安装则安装pip工具,安装则请跳过这一步
python get-pip.py
安装完毕以后退回第一步重新检测,现在安装pygame
python -m pip install pygame --user
或者通过pycharm安装第三个库,现在导入pygame即可
import pygame
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameimport sys # 用于退出游戏def run_game(): # 初始化游戏 pygame.init() # 设置屏幕的分辨率 screen = pygame.display.set_mode((1000, 600)) # 大小为1000px乘以600px # 打印其类型 # print(type(screen)) # >class 'pygame.Surface'< pygame.display.set_caption("飞机大战") # 标题 # 存储背景的变量 bg_img = pygame.image.load("./imgs/bg_img.png") # 相对路径 print(bg_img) # 开始游戏的主循环 while True: # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): # 每次循环都会重新绘制屏幕 screen.blit(bg_img, [0, 0]) # 绘制图像 if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() # 将完整显示Surface更新到屏幕 pygame.display.flip()run_game()
display.set_mode返回的是一个Surface数据类型
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameclass Settings: """存储飞机大战的所有设置""" def __init__(self): # 屏幕设置 self.screen_width = 1000 self.screen_height = 600 self.bg_img = pygame.image.load("./imgs/bg_img.png")# 现在来改写plane_war.py"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameimport sys # 用于退出游戏from settings import Settings # 引入settings.pydef run_game(): # 初始化游戏 pygame.init() # 设置屏幕的分辨率 setting = Settings() screen = pygame.display.set_mode((setting.screen_width, setting.screen_height)) pygame.display.set_caption("飞机大战") # 标题 # 开始游戏的主循环 while True: # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): # 每次循环都会重新绘制屏幕 screen.blit(setting.bg_img, [0, 0]) # 绘制图像 if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() # 将完整显示Surface更新到屏幕 pygame.display.flip()run_game()
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameclass Plane: def __init__(self, screen): # 初始化小飞机并设置其初始位置 self.screen = screen # 加载图像,并获得其矩形区域 self.img_plane = pygame.image.load("./imgs/plane.png") self.rect = self.img_plane.get_rect() # 得到小飞机的的矩形区域 self.screen_rect = self.screen.get_rect() # 得到screen的矩形区域 # 将小飞机放到底部中央 self.rect.centerx = self.screen_rect.centerx # 水平居中 self.rect.bottom = self.screen_rect.bottom # 底部 def blitme(self): # 在指定位置绘制小飞机 self.screen.blit(self.img_plane, self.rect)
get_rect会返回Surface的矩形的区域,.centerx和.bottom是其两个属性改写plane_war.py将小飞机绘制在屏幕上
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameimport sys # 用于退出游戏from settings import Settings # 引入settings.pyfrom plane import Planedef run_game(): # 初始化游戏 pygame.init() # 设置屏幕的分辨率 setting = Settings() screen = pygame.display.set_mode((setting.screen_width, setting.screen_height)) # 大小为1000px乘以600px pygame.display.set_caption("飞机大战") # 标题 # 创建小飞机 plane = Plane(screen) # 开始游戏的主循环 while True: # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): # 每次循环都会重新绘制屏幕 screen.blit(setting.bg_img, [0, 0]) # 绘制图像 plane.blitme() # 将飞船绘制到屏幕上 if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() # 将完整显示Surface更新到屏幕 pygame.display.flip()run_game()
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import sysimport pygamedef check_events(): # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit()def update_screen(screen, bg_img, plane): # 更新屏幕的图像 # 每次循环都会重新绘制屏幕 screen.blit(bg_img, [0, 0]) # 绘制图像 plane.blitme() # 将飞船绘制到屏幕上 # 将完整显示Surface更新到屏幕 pygame.display.flip()
check_events函数用来完成窗口不会关闭的功能,update_screen用来完成更新图像的功能,有3个形参,Surface对象、背景图像、小飞机函数因为check_events完成了退出游戏的操作,所以plane_war.py就不需要sys模块了,更新后的plane_war.py如下
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygamefrom settings import Settings # 引入settings.pyfrom plane import Planeimport game_func as fgdef run_game(): # 初始化游戏 pygame.init() # 设置屏幕的分辨率 setting = Settings() screen = pygame.display.set_mode((setting.screen_width, setting.screen_height)) # 大小为1000px乘以600px pygame.display.set_caption("飞机大战") # 标题 # 创建小飞机 plane = Plane(screen) # 开始游戏的主循环 while True: # 不关闭窗口 fg.check_events() # 绘制图像 fg.update_screen(screen, setting.bg_img, plane)run_game()
def check_events(plane): # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: # 小飞机往又移动 plane.rect.centerx += 1
现在按一下小飞机移动一个像素,一般的游戏都是通过按下不送则一直移动,Pygame中的pygame.KEYUP可以检测用户是否松开按键 现在结合KEYDOWN和KEYUP来完成一个持续移动
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameclass Plane: def __init__(self, screen): # 初始化小飞机并设置其初始位置 self.screen = screen # 加载图像,并获得其矩形区域 self.img_plane = pygame.image.load("./imgs/plane.png") self.rect = self.img_plane.get_rect() # 得到小飞机的的矩形区域 self.screen_rect = self.screen.get_rect() # 得到screen的矩形区域 # print(self.screen_rect) # 将小飞机放到底部中央 self.rect.centerx = self.screen_rect.centerx # 水平居中 self.rect.bottom = self.screen_rect.bottom # 底部 # 标志位 self.mv_right = False # 定义一个调整小飞机位置的方法 def update(self): # 根据标志位的调整小飞机的位置 if self.mv_right: self.rect.centerx += 1 def blitme(self): # 在指定位置绘制小飞机 self.screen.blit(self.img_plane, self.rect)
update方法是标志位为True时,小飞机就开始移动改写game_func.py中的check_events函数
def check_events(plane): # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: # 当用户按下键位时标志位为True plane.mv_right = True elif event.type == pygame.KEYUP: if event.key == pygame.K_RIGHT: # 当用户松开键位为false plane.mv_right = False
最后只要在plane_war.py中调用update方法就可以完成持续移动的操作
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameclass Plane: def __init__(self, screen): # 初始化小飞机并设置其初始位置 self.screen = screen # 加载图像,并获得其矩形区域 self.img_plane = pygame.image.load("./imgs/plane.png") self.rect = self.img_plane.get_rect() # 得到小飞机的的矩形区域 self.screen_rect = self.screen.get_rect() # 得到screen的矩形区域 # print(self.screen_rect) # 将小飞机放到底部中央 self.rect.centerx = self.screen_rect.centerx # 水平居中 self.rect.bottom = self.screen_rect.bottom # 底部 # 标志位 self.mv_right = False self.mv_left = False # 定义一个调整小飞机位置的方法 def update(self): # 根据标志位的调整小飞机的位置 if self.mv_right: self.rect.centerx += 1 if self.mv_left: self.rect.centerx -= 1 def blitme(self): # 在指定位置绘制小飞机 self.screen.blit(self.img_plane, self.rect)
改写后的game_func.py中的check_events函数
def check_events(plane): # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: # 当用户按下键位时标志位为True plane.mv_right = True elif event.key == pygame.K_LEFT: plane.mv_left = True elif event.type == pygame.KEYUP: if event.key == pygame.K_RIGHT: # 当用户松开键位为false plane.mv_right = False elif event.key == pygame.K_LEFT; plane.mv_left = False
self.plane_speed = 2.5
现在对plane.py做修改
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygameclass Plane: def __init__(self, screen, setting): # 初始化小飞机并设置其初始位置 self.screen = screen self.setting = setting # 实例化属性 # 加载图像,并获得其矩形区域 self.img_plane = pygame.image.load("./imgs/plane.png") self.rect = self.img_plane.get_rect() # 得到小飞机的的矩形区域 self.screen_rect = self.screen.get_rect() # 得到screen的矩形区域 # print(self.screen_rect) # 将小飞机放到底部中央 self.rect.centerx = self.screen_rect.centerx # 水平居中 self.rect.bottom = self.screen_rect.bottom # 底部 # 将其修改为浮点数 self.center = float(self.rect.centerx) # 标志位 self.mv_right = False self.mv_left = False # 定义一个调整小飞机位置的方法 def update(self): # 根据标志位的调整小飞机的位置 if self.mv_right: self.center += self.setting.plane_speed # settings中的属性 if self.mv_left: self.center -= self.setting.plane_speed # 根据self.center的值来更新self.rect.centerx self.rect.centerx = self.center def blitme(self): # 在指定位置绘制小飞机 self.screen.blit(self.img_plane, self.rect)
将plane_war.py中的plane增加一个属性
plane = Plane(screen, setting)
def check_keydown_events(event, plane): # 捕捉用户按下 if event.key == pygame.K_RIGHT: # 当用户按下键位时标志位为True plane.mv_right = True elif event.key == pygame.K_LEFT: plane.mv_left = Truedef check_keyup_events(event, plane): # 捕捉用户松开 if event.key == pygame.K_RIGHT: # 当用户松开键位为false plane.mv_right = False elif event.key == pygame.K_LEFT: plane.mv_left = Falsedef check_events(plane): # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() elif event.type == pygame.KEYDOWN: check_keydown_events(event, plane) elif event.type == pygame.KEYUP: check_keyup_events(event, plane)
# 子弹的设置self.bullet_speed = 3 # 速度self.bullet_width = 3 # 子弹的宽self.bullet_height = 15 # 子弹的高self.bullet_color = 100, 100, 100 # 子弹的颜色
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygamefrom pygame.sprite import Spriteclass Bullet(Sprite): # 继承pygame.sprite中的Sprite类 """子弹的管理""" def __init__(self, setting, screen, plane): super().__init__() self.screen = screen # 在(0,0)处创建一个表示子弹的矩形 # pygame.Rect # 用于存储直角坐标的pygame对象 self.rect = pygame.Rect(0,0, setting.self.bullet_width, setting.self.bullet_height) # 设置显示的位置 self.rect.centerx = plane.rect.centerx self.rect.top = plane.rect.top # 让子弹的位置跟小飞机重叠,当子弹飞出了以后,就显得跟从小飞机里面射出来一样 # 将子弹的坐标转换为浮点数 self.y = float(self.rect.y) # 子弹的颜色 self.color = setting.bullet.color # 子弹的速度 self.speed = setting.bullet.speed def update(self): # 向上移动子弹 self.y -= self.speed # 根据self.y的值更新self.rect.y self.rect.y = self.y def draw_bullet(self): """绘制子弹""" # pygame.draw.rect()画一个矩形的形状 pygame.draw.rect(self.screen, self.color, self.rect)
Bullet类继承于pygame.sprite中的Sprite类,此类可以将游戏中的元素进行编组,可以同时操作编组中的所有元素
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygamefrom settings import Settingsfrom plane import Planeimport game_func as fgfrom pygame.sprite import Groupdef run_game(): # 初始化游戏 pygame.init() # 设置屏幕的分辨率 setting = Settings() screen = pygame.display.set_mode((setting.screen_width, setting.screen_height)) # 大小为1000px乘以600px pygame.display.set_caption("飞机大战") # 标题 # 创建一个存储子弹的编组 bullets = Group() # 创建小飞机 plane = Plane(screen, setting) # 开始游戏的主循环 while True: # 不关闭窗口 fg.check_events(plane, setting, screen, bullets) # 调用小飞机移动的方法 plane.update() bullets.update() # 绘制图像 fg.update_screen(screen, setting.bg_img, plane, bullets)run_game()
开火
通过修改game_func.py中的函数来完成发射子弹的操作
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import sysfrom bullet import Bulletimport pygamedef check_keydown_events(event, plane, setting, screen, bullets): # 捕捉用户按下 if event.key == pygame.K_RIGHT: # 当用户按下键位时标志位为True plane.mv_right = True elif event.key == pygame.K_LEFT: plane.mv_left = True elif event.key == pygame.K_SPACE: # 创建一个子弹,并将其加入到编组bullets中 new_bullet = Bullet(setting, screen, plane) bullets.add(new_bullet)def check_keyup_events(event, plane): # 捕捉用户松开 if event.key == pygame.K_RIGHT: # 当用户松开键位为false plane.mv_right = False elif event.key == pygame.K_LEFT: plane.mv_left = Falsedef check_events(plane, setting, screen, bullets): # 为了防止游戏窗口启动会立马关闭,在其中增加一个游戏循环(无限循环), for event in pygame.event.get(): if event.type == pygame.QUIT: # QUIT用户请求程序关闭 sys.exit() elif event.type == pygame.KEYDOWN: check_keydown_events(event, plane, setting, screen, bullets) elif event.type == pygame.KEYUP: check_keyup_events(event, plane)def update_screen(screen, bg_img, plane, bullets): # 更新屏幕的图像 # 每次循环都会重新绘制屏幕 screen.blit(bg_img, [0, 0]) # 绘制图像 # 绘制子弹 for bullet in bullets.sprites(): bullet.draw_bullet() # 绘制子弹 plane.blitme() # 将飞船绘制到屏幕上 # 将完整显示Surface更新到屏幕 pygame.display.flip()
用户按下空格之后会创建一个子弹(一个名为new_bullet的Bullet实例),并使用add追加到编组中 方法bullets.sprites返回一个列表,包含了编组中的所有精灵,遍历编组中的精灵,并通过draw_bullet()绘制到屏幕上现在已经完成基本的射击功能了,虽然子弹到达屏幕顶端后消失了,这仅仅是因为pygame无法绘制屏幕外面的东西,这些子弹实际还是存在的,他们的y坐标为负数且越来越少,会继续消耗内存。
# 删除已经消失的子弹for bullet in bullets.copy(): if bullet.rect.bottom >= 0: bullets.remove(bullet)# print(len(bullets)) # 用于测试子弹是否删除
注意:在fg.update_screen之前进行添加
# 限制子弹的数量self.bullet_allowed = 5
在check_keydown_events函数体中增加一个判断即可
def update_bullets(bullets): # 将编组中的每个子弹调用bullet.update() bullets.update() # 删除已经消失的子弹 for bullet in bullets.copy(): if bullet.rect.bottom >= 0: bullets.remove(bullet)
此时的while语句中就4行代码
while True: fg.check_events(plane, setting, screen, bullets) # 不关闭窗口 plane.update() # 调用小飞机移动的方法 fg.update_bullets(bullets) # 绘制子弹 fg.update_screen(screen, setting.bg_img, plane, bullets) # 绘制图像
"""-*- coding:uft-8 -*-author: 小甜date:2020/6/4"""import pygamefrom pygame.sprite import Spriteclass Spaceship(Sprite): '''表示飞船的类''' def __init__(self, setting, screen): super().__init__() self.screen = screen self.setting = setting # 添加飞船图像 self.img = pygame.image.load("./imgs/enemy.png") # 获取rect属性 self.rect = self.img.get_rect() # 每个飞船最初都在屏幕左上角附近 self.rect.x = self.rect.width # 飞船图像的左边距等于图像的宽度 self.rect.y = self.rect.height # 飞船图书的上边距等于图像的高度 self.x = float(self.rect.x) def blitme(self): # 绘制飞船图像 self.screen.blit(self.img, self.rect)
这里除了位置基本与Plane类相同
实例化Spaceship类在plane_war.py中添加Spaceship实例"""-*- coding:uft-8 -*-author: 小甜date:2020/6/3"""import pygamefrom settings import Settings # 引入settings.pyfrom plane import Planeimport game_func as fgfrom pygame.sprite import Groupfrom spaceship import Spaceshipdef run_game(): # 初始化游戏 pygame.init() # 设置屏幕的分辨率 setting = Settings() screen = pygame.display.set_mode((setting.screen_width, setting.screen_height)) # 大小为1000px乘以600px pygame.display.set_caption("飞机大战") # 标题 # 创建一个存储子弹的编组 bullets = Group() # 创建小飞机 plane = Plane(screen, setting) # 创建飞船 spaceship = Spaceship(setting, screen) # 开始游戏的主循环 while True: # 不关闭窗口 fg.check_events(plane, setting, screen, bullets) # 调用小飞机移动的方法 plane.update() # 绘制子弹 fg.update_bullets(bullets) # 绘制图像 fg.update_screen(screen, setting.bg_img, plane, bullets, spaceship)run_game()
这里导入了一下新创建的Spaceship类,在while循环外创建一个实例,给update_screen传递一个飞船的实例
def update_screen(screen, bg_img, plane, bullets, spaceship): # 更新屏幕的图像 # 每次循环都会重新绘制屏幕 screen.blit(bg_img, [0, 0]) # 绘制图像 # 绘制子弹 for bullet in bullets.sprites(): bullet.draw_bullet() # 绘制子弹 plane.blitme() # 将飞船绘制到屏幕上 # 绘制飞船 spaceship.blitme() # 将完整显示Surface更新到屏幕 pygame.display.flip()
这就是创建飞机大战地图的过程,实施的过程后续在发~
本文参考美国作家埃里克·马瑟斯《Python编程从入门到精通》
推荐阅读
知乎大V:业务用得到的是数据分析技巧都在这
突发!Windows XP 源代码泄露
看黄片,起诉网站,可尼玛太秀了推荐我的微信号
加微信围观朋友圈,送Python资料,接私活、职场建议高质量交流学习
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。