Pygame是一组专门编写游戏的python模块,具有高度的可移植性。下面将介绍Pygame中提供的方法,实现一个简单的飞机大战小demo,扫描下方二维码关注我的公众号中回复“飞机大战”,即可获取demo的代码地址、本demo素材(彩色图片素材、微信经典黑白素材、音效)
本文主要内容
- 通过例子示范窗口绘制及其所需函数简要说明
- 图片移动、通过用户事件移动图片及所需函数简要说明
- 碰撞检测及所需函数简要说明
- 音频加载及所需函数简要说明
- 成果展示
环境
- python3.6+
- windows/linux
模块安装
pip install pygame
游戏窗口建立及所需函数简要说明
import os
import time
import pygame
# 屏幕宽度
SCREEN_WIDTH = 500
# 屏幕高度
SCREEN_HEIGHT = 250
# 图片绝对路径
IMG_PATH = os.path.join(os.getcwd(), "img")
def main():
# 初始化显示模块
pygame.display.init()
# 创建窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption("python小demo 飞机大战")
# 设置窗口icon
pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH, "icon.jpg")))
# 加载背景图片
background = pygame.image.load(os.path.join(IMG_PATH, "test_bj.png"))
while True:
# 将背景图片绘制到窗口上
screen.blit(background, (0, 0))
# 更新屏幕上内容
pygame.display.update()
time.sleep(0.02)
if __name__ == "__main__":
main()
查看下效果:
x、y是我手动绘制的,让大家可以更加直观的看到窗口坐标轴情况
所需函数简要说明
display.init() -> None
# 该函数只做初始化显示模块,且不返回任何东西
# 如果在使用display其他方法未初始化,会自动调用
display.set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface
# 该函数会创建并返回一个Surface的窗口对象
# 参数:
# size=(0, 0) 设置窗口大小,第一个是屏幕宽度,第二个是窗口高度
# flags 控制您想要的显示类型,例如是否全屏,可选参数:
# pygame.FULLSCREEN:创建一个全屏
# pygame.DOUBLEBUF:双缓冲模式,推荐和HWSURFACE或OPENGL一起使用
# pygame.HWSURFACE:硬件加速,只有在 FULLSCREEN 下可以使用
# pygame.OPENGL:创建一个 OPENGL 渲染的显示
# pygame.RESIZABLE:创建一个可调整尺寸的窗口
# pygame.NOFRAME:创建一个没有边框和控制按钮的窗口
# 可以使用按位或选择多个参数,如:
# flags = pygame.OPENGL | pygame.FULLSCREEN
# depth 参数表示颜色位数,不建议传递,默认会选择最佳的颜色深度
# display 窗口索引,默认0
# vsync 传入1时,可以获得垂直同步显示,只有同时设置了pygame.OPENGL、
# pygame.FULLSCREEN才能传值
display.set_caption(title, icontitle=None) -> None
# 设置窗口标题
# 参数:
# title 窗口的标题
# icontitle 部分系统支持最小窗口时切换标题栏
display.set_icon(Surface) -> None
# 设置窗口LOGO
# 参数:
# Surface 可以传入任何Surface对象作为图标,但大多数系统要求大小是32*32
display.update(rectangle=None) -> None
display.update(rectangle_list) -> None
# 更新屏幕内容显示,如果设置了pygame.OPENGL情况下调用,会触发异常
# 参数:
# rectangle 一个矩形区域
# rectangle_list 多个矩形区域
# 如果传入None或者空列表,就会更新整个窗口
image.load(filename) -> Surface
# 加载图像,返回一个Surface对象,pygame支持常见PNG、JPG、GIF等格式图片
#参数:
# filename 图片路径,兼容运行环境,路径建议通过os.path.join()获取
Surface.blit(source, dest, area=None, special_flags=0) -> Rect
# 将图像绘制到另外一个图像上,返回值是一个Rect对象,表示在screen上绘制的矩形区域
# 参数:
# source 矩形图像的Surface实例对象
# dest 是坐标对象,绘制在屏幕的坐标
# area 表示从scorce的area区域取出绘制的到Surface对象上
# 结合上面例子
# background = pygame.image.load(os.path.join(IMG_PATH, "test_bj.png"))
# screen.blit(background, (0, 0))
# 就是将background图片绘制到screen屏幕的0, 0坐标处
Surface.get_rect(**kwargs) -> Rect
# 获取Surface的矩形区域,该矩形区域始终从坐标0, 0开始,宽度和高度与图片大小相同
# 返回一个rect对象,rect对象记录着Surface的属性信息,如:
# rect.x Surface对象x轴坐标
# rect.y Surface对象y轴坐标
# rect.width Surface对象的宽度
# rect.height Surface对象的高度
图片移动、通过用户事件移动图片
上面代码已经能够建立游戏窗口和加载背景图,现在创建英雄,通过改变坐标实现移动
import os
import time
import pygame
# 屏幕宽度
SCREEN_WIDTH = 500
# 屏幕高度
SCREEN_HEIGHT = 250
# 图片绝对路径
IMG_PATH = os.path.join(os.getcwd(), "img")
class HeroPlane(object):
def __init__(self):
super(HeroPlane, self).__init__()
self.image = pygame.image.load(os.path.join(IMG_PATH, "hero_show_1.png"))
self.rect = self.image.get_rect()
self.rect.x = 0 # 飞机x轴位置
self.rect.y = int(SCREEN_HEIGHT - self.rect.height) / 2 # 飞机y轴位置
self.is_running = True
self.bullet_list = pygame.sprite.Group()
self.last_time = time.time()
def move_level(self, level):
# 防止飞机移出屏幕外, 增加判断
add_level = self.rect.x + level
if 0 <= add_level <= SCREEN_WIDTH - self.rect.width:
self.rect.x = add_level
elif add_level < 0:
self.rect.x = 0
elif add_level > SCREEN_WIDTH - self.rect.width:
self.rect.x = SCREEN_WIDTH - self.rect.width
def move_vertical(self, vertical):
add_vertical = self.rect.y + vertical
if 0 <= add_vertical <= SCREEN_HEIGHT - self.rect.height:
self.rect.y = add_vertical
elif add_vertical < 0:
self.rect.y = 0
elif add_vertical > SCREEN_HEIGHT - self.rect.height:
self.rect.y = SCREEN_HEIGHT - self.rect.height
def main():
pygame.display.init()
# 初始化显示模块
# pygame.display.init()
# 创建窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption("python小demo 飞机大战")
# 设置窗口icon
pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH, "icon.jpg")))
# 加载背景图片
background = pygame.image.load(os.path.join(IMG_PATH, "test_bj.png"))
# 初始化英雄类
hero = HeroPlane()
def update_hero():
hero.move_level(2)
screen.blit(hero.image, (hero.rect.x, hero.rect.y))
while True:
# 将背景图片绘制到窗口上
screen.blit(background, (0, 0))
# 更新英雄在屏幕上的位置
update_hero()
# 更新屏幕上内容
pygame.display.update()
time.sleep(0.02)
if __name__ == "__main__":
main()
执行效果如下:
上面加载英雄并且实现英雄移动,其实就是不断改变图片在屏幕中的绘制位置。主函数的time.sleep也可以替换成pygame.time.Clock.tick方法,但本例子中,效果偏差不远,就没有使用pygame.time提供的时间模块
上面代码虽然能够实现英雄的移动,但是无法根据玩家操作控制英雄的移动,这时候我们就需要提供特定的键盘或者鼠标事件控制英雄移动,下面示例按住鼠标实现飞机移动
import os
import sys
import time
import pygame
# 屏幕宽度
SCREEN_WIDTH = 500
# 屏幕高度
SCREEN_HEIGHT = 250
# 图片绝对路径
IMG_PATH = os.path.join(os.getcwd(), "img")
# 鼠标按键标识
MOUSE_MOVE = False
class HeroPlane(object):
def __init__(self):
super(HeroPlane, self).__init__()
self.image = pygame.image.load(os.path.join(IMG_PATH, "hero_show_1.png"))
self.rect = self.image.get_rect()
self.rect.x = 0 # 飞机x轴位置
self.rect.y = int(SCREEN_HEIGHT - self.rect.height) / 2 # 飞机y轴位置
self.is_running = True
self.bullet_list = pygame.sprite.Group()
self.last_time = time.time()
def move_level(self, level):
# 防止飞机移出屏幕外, 增加判断
if 0 <= level <= SCREEN_WIDTH - self.rect.width:
self.rect.x = level
elif level < 0:
self.rect.x = 0
elif level > SCREEN_WIDTH - self.rect.width:
self.rect.x = SCREEN_WIDTH - self.rect.width
def move_vertical(self, vertical):
if 0 <= vertical <= SCREEN_HEIGHT - self.rect.height:
self.rect.y = vertical
elif vertical < 0:
self.rect.y = 0
elif vertical > SCREEN_HEIGHT - self.rect.height:
self.rect.y = SCREEN_HEIGHT - self.rect.height
def main():
pygame.init()
# 初始化显示模块
pygame.display.init()
# 创建窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption("python小demo 飞机大战")
# 设置窗口icon
pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH, "icon.jpg")))
# 加载背景图片
background = pygame.image.load(os.path.join(IMG_PATH, "test_bj.png"))
# 初始化英雄类
hero = HeroPlane()
def event_check():
"""
事件检测,这边做了一个简单的示例
return:
"""
global MOUSE_MOVE
for event in pygame.event.get():
if event.type == pygame.QUIT:
# 接收到退出事件后退出程序
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
MOUSE_MOVE = True
elif event.type == pygame.MOUSEBUTTONUP:
MOUSE_MOVE = False
if MOUSE_MOVE:
x, y = pygame.mouse.get_pos()
hero.move_level(x)
hero.move_vertical(y)
def update_hero():
screen.blit(hero.image, (hero.rect.x, hero.rect.y))
while True:
# 事件检测
event_check()
# 将背景图片绘制到窗口上
screen.blit(background, (0, 0))
# 更新英雄在屏幕上的位置
update_hero()
# 更新屏幕上内容
pygame.display.update()
time.sleep(0.02)
if __name__ == "__main__":
main()
执行效果如下:
所需函数简要说明
event.get(eventtype=None) -> Eventlist
event.get(eventtype=None, pump=True) -> Eventlist
# 获取事件队列
# 参数:
# eventtype 可以传入你想要监听到的事件列表,如果不传,会把所有用户触发的事件返回
# 如上面示例中只监听了三个事件,也可以:
# pygame.event.get([pygame.QUIT, pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP])
# 但如果设置了指定类型事件,其他事件将不会被获取,存在了事件队列中中,有可能导致事件队列被堆满
# pump 默认为False,如果设置为True,event.pump()将会被调用
# 返回事件列表
# 常见事件类型:
# 事件 产生途径 参数
# QUIT 用户按下关闭按钮 none
# KEYDOWN 键盘被按下 unicode, key, mod
# KEYUP 键盘被放开 key, mod
# MOUSEMOTION 鼠标移动 pos, rel, buttons
# MOUSEBUTTONDOWN 鼠标按下 pos, button
# MOUSEBUTTONUP 鼠标放开 pos, button
# USEREVENT 用户自定义事件 code
# 上面列举了常见的事件,更多事件和方法可以点击上面文档链接查阅文档
- pygame.key用于处理键盘的模块,当键盘按下或者释放时,pygame.event.get()就能获取pygame.KEYDOWN或pygame.KEYUP事件,这两个事件都有key和mod属性:key代表键盘上每个整数ID;mod代表事件发生时修饰建位掩码。
上述例子中,如果想通过长按键盘⬅、⬆、⬇、➡控制英雄,可将事件处理函数修改为:
def event_check():
"""
事件检测,这边做了一个简单的示例
return:
"""
# 设置KEYDOWN标志位,0代表键盘已释放,1、2、3、4分别代表⬅、⬆、⬇、➡
global KEYDOWN
for event in pygame.event.get():
if event.type == pygame.QUIT:
# 接收到退出事件后退出程序
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
KEYDOWN = 1
elif event.key == pygame.K_UP:
KEYDOWN = 2
elif event.key == pygame.K_DOWN:
KEYDOWN = 3
elif event.key == pygame.K_RIGHT:
KEYDOWN = 4
elif event.type == pygame.KEYUP:
KEYDOWN = 0
if KEYDOWN:
if KEYDOWN == 1:
hero.move_level(hero.rect.x - 5)
elif KEYDOWN == 2:
hero.move_vertical(hero.rect.y - 5)
elif KEYDOWN == 3:
hero.move_vertical(hero.rect.y + 5)
else:
hero.move_level(hero.rect.x + 5)
下面列举常见的键盘常量(更多键盘常量可点击上方链接查阅文档):
KeyASCII | 描述 |
---|---|
K_BACKSPACE | 退格键(Backspace) |
K_TAB | 制表键(Tab) |
K_CLEAR | 清除键(Clear) |
K_RETURN | 回车键(Enter) |
K_ESCAPE | 退出键(Escape) |
K_DELETE | 删除键(delete) |
K_0 - K_9 | 0 - 9 |
K_a - K_z | a - z |
K_KP0 - K_KP9 | 0 - 9(小键盘) |
K_UP | 向上箭头(up arrow) |
K_DOWN | 向下箭头(down arrow) |
K_RIGHT | 向右箭头(right arrow) |
K_LEFT | 向左箭头(left arrow) |
碰撞检测及所需函数简要说明
上面代码中,已经实现创建英雄,并且能通过事件去控制英雄的移动,下面我们可以按照创建英雄的方法,创建一个敌机,并通过让英雄与敌机碰撞发生爆炸
import os
import sys
import time
import pygame
# 屏幕宽度
SCREEN_WIDTH = 500
# 屏幕高度
SCREEN_HEIGHT = 250
# 图片绝对路径
IMG_PATH = os.path.join(os.getcwd(), "img")
# 鼠标按键标识
MOUSE_MOVE = False
# 键盘长按标识位
KEYDOWN = 0
class HeroPlane(object):
def __init__(self):
super(HeroPlane, self).__init__()
self.image = pygame.image.load(os.path.join(IMG_PATH, "hero_show_1.png"))
self.rect = self.image.get_rect()
self.rect.x = 0 # 飞机x轴位置
self.rect.y = int(SCREEN_HEIGHT - self.rect.height) / 2 # 飞机y轴位置
self.is_running = True
def move_level(self, level):
# 防止飞机移出屏幕外, 增加判断
if 0 <= level <= SCREEN_WIDTH - self.rect.width:
self.rect.x = level
elif level < 0:
self.rect.x = 0
elif level > SCREEN_WIDTH - self.rect.width:
self.rect.x = SCREEN_WIDTH - self.rect.width
def move_vertical(self, vertical):
if 0 <= vertical <= SCREEN_HEIGHT - self.rect.height:
self.rect.y = vertical
elif vertical < 0:
self.rect.y = 0
elif vertical > SCREEN_HEIGHT - self.rect.height:
self.rect.y = SCREEN_HEIGHT - self.rect.height
class EnemyPlane(pygame.sprite.Sprite):
def __init__(self):
super(EnemyPlane, self).__init__()
self.image = pygame.image.load(os.path.join(IMG_PATH, "mp_show_3.png"))
self.rect = self.image.get_rect()
self.rect = self.image.get_rect()
self.rect.x = int(SCREEN_WIDTH - self.rect.width) # 飞机x轴位置
self.rect.y = int(SCREEN_HEIGHT - self.rect.height) / 2 # 飞机y轴位置
self.is_running = True
def main():
pygame.init()
# 初始化显示模块
pygame.display.init()
# 创建窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption("python小demo 飞机大战")
# 设置窗口icon
pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH, "icon.jpg")))
# 加载背景图片
background = pygame.image.load(os.path.join(IMG_PATH, "test_bj.png"))
# 初始化英雄
hero = HeroPlane()
# 初始化敌机
enemy = EnemyPlane()
def event_check():
"""
事件检测,这边做了一个简单的示例
return:
"""
global MOUSE_MOVE
for event in pygame.event.get():
if event.type == pygame.QUIT:
# 接收到退出事件后退出程序
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
MOUSE_MOVE = True
elif event.type == pygame.MOUSEBUTTONUP:
MOUSE_MOVE = False
if MOUSE_MOVE:
x, y = pygame.mouse.get_pos()
hero.move_level(x)
hero.move_vertical(y)
# def event_check():
# """
# 事件检测,这边做了一个简单的示例
# return:
# """
# # 设置KEYDOWN标志位,0代表键盘已释放,1、2、3、4分别代表⬅、⬆、⬇、➡
# global KEYDOWN
#
# for event in pygame.event.get():
# if event.type == pygame.QUIT:
# # 接收到退出事件后退出程序
# pygame.quit()
# sys.exit()
# elif event.type == pygame.KEYDOWN:
# if event.key == pygame.K_LEFT:
# KEYDOWN = 1
# elif event.key == pygame.K_UP:
# KEYDOWN = 2
# elif event.key == pygame.K_DOWN:
# KEYDOWN = 3
# elif event.key == pygame.K_RIGHT:
# KEYDOWN = 4
# elif event.type == pygame.KEYUP:
# KEYDOWN = 0
#
# if KEYDOWN:
# if KEYDOWN == 1:
# hero.move_level(hero.rect.x - 5)
# elif KEYDOWN == 2:
# hero.move_vertical(hero.rect.y - 5)
# elif KEYDOWN == 3:
# hero.move_vertical(hero.rect.y + 5)
# else:
# hero.move_level(hero.rect.x + 5)
def update_hero():
screen.blit(hero.image, (hero.rect.x, hero.rect.y))
def update_enemy():
screen.blit(enemy.image, (enemy.rect.x, enemy.rect.y))
def check_crash():
is_crash = pygame.sprite.collide_rect(hero, enemy)
if is_crash:
# 先展示飞机爆炸,然后在屏幕中间写下game over提示
screen.blit(pygame.image.load(os.path.join(IMG_PATH, "ex_2.png")), (hero.rect.x, hero.rect.y))
screen.blit(pygame.image.load(os.path.join(IMG_PATH, "ex_2.png")), (enemy.rect.x, enemy.rect.y))
game_over = pygame.font.Font(None, 100)
game_over = game_over.render("game over", True, (220, 20, 60))
screen.blit(game_over, [int(SCREEN_WIDTH / 2 - game_over.get_width() / 2), int(SCREEN_HEIGHT / 2)])
while True:
# 事件检测
event_check()
# 将背景图片绘制到窗口上
screen.blit(background, (0, 0))
# 更新英雄在屏幕上的位置
update_hero()
# 更新敌机在屏幕上位置
update_enemy()
# 碰撞检测
check_crash()
# 更新屏幕上内容
pygame.display.update()
time.sleep(0.02)
if __name__ == "__main__":
main()
执行效果如下:
所需函数简要说明
- pygame.sprite 基本游戏对象类,上面例子中,我们英雄跟敌机都继承了pygame.sprite.Sprite,这是方便我们省略了造轮子的步骤,比如碰撞检测。
sprite.collide_rect(left, right) -> bool
# 检测两个继承了pygame.sprite.Sprite且具有矩形区域属性的对象是否发生了碰撞
# 该方法会根据对象的rect属性判断是否发生了碰撞
# 参数:
# left 第一个对象,如hero
# right 第二个对象,如hero
# 返回bool值, 真为发生碰撞,假为没有碰撞
# 该示例中,只有一架敌机和一架英雄,但如果需要英雄与多架敌机发生碰撞
# 或者英雄发出的子弹是否击中了敌机,这就产生了一对多、多对多的检测
# 这种情况可以使用sprite.Group来完成该方法
sprite.Group() -> Group
# 用于保存和管理多个 Sprite 对象的容器类
# 返回一个组对象
sprite.Group.add(*sprites) -> None
# 增加一个sprites到该组中
sprite.spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
# 查找一个sprite是否与sprite.Group()中的sprite发生碰撞
# 用于一对多的碰撞检测
# 参数:
# sprite 单个sprite对象
# group 一个包含多个sprite对象的组对象
# dokill bool值,如果为真,发生碰撞时,将碰撞的sprite对象从组中移除
# collided 是一个判断碰撞的函数,参数为两个sprite对象,并且需要返回bool值,如果你的
# sprite对象也有像例子中设置了rect属性,可以不传
# 返回所有和sprite发生碰撞的对象,如果没有,返回空Sprite_list
sprite.groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
# 查找两组中所有碰撞的Sprite对象
# 用于实现多对多碰撞检测
# 参数:
# group1 第一个sprite对象的组对象
# group2 第二个sprite对象的组对象
# dokill1 bool值,如果为真,发生碰撞时,将碰撞的sprite对象从第一个组中移除
# dokill2 bool值,如果为真,发生碰撞时,将碰撞的sprite对象从第二个组中移除
# collided 是一个判断碰撞的函数,参数为两个sprite对象,并且需要返回bool值,如果你的
# sprite对象也有像例子中设置了rect属性,可以不传
# 返回一个Sprite_dict对象,类似于:
# {<group1 Sprite(in 1 groups)>: [<group2 Sprite(in 1 groups)>]}
# key 是group1 碰撞列表, value是group2碰撞列表
# 上面列举了本例需要的函数,更多使用方法可以点击上面文档链接查阅文档
- pygame.font 用于加载和渲染字体
font.Font(filename, size) -> Font
font.Font(object, size) -> Font
# 从给定的文件名或者python的文件对象加载新字体
# 参数:
# filename 文件路径字符串,如os.path.join('fonts', 'ziti.ttf')
# object python文件对象
# 如果第一个参数传None,会使用默认字体
# size 整数类型,字体大小
# 返回一个Font对象
font.Font.render(text, antialias, color, background=None) -> Surface
# 创建一个新的 Surface,其上呈现了指定的文本,该方法只能写一行文字,不呈现换行,空字符串会引发异常
# 参数:
# text 要展示的文本
# antialias bool值,如果为真,字符将有平滑的边缘
# color 字体颜色 RGB值
# background 用于文本背景颜色,如果没有传递,背景色是透明色
# 上面列举了本例需要的函数,更多使用方法可以点击上面文档链接查阅文档
音频加载及所需函数简要说明
import os
import sys
import time
import pygame
# 屏幕宽度
SCREEN_WIDTH = 500
# 屏幕高度
SCREEN_HEIGHT = 250
# 图片绝对路径
IMG_PATH = os.path.join(os.getcwd(), "img")
# 鼠标按键标识
MOUSE_MOVE = False
# 键盘长按标识位
KEYDOWN = 0
# 背景音乐路径
MUSIC_PATH = os.path.join(os.getcwd(), "sound")
class HeroPlane(pygame.sprite.Sprite):
def __init__(self):
super(HeroPlane, self).__init__()
self.image = pygame.image.load(os.path.join(IMG_PATH, "hero_show_1.png"))
self.rect = self.image.get_rect()
self.rect.x = 0 # 飞机x轴位置
self.rect.y = int(SCREEN_HEIGHT - self.rect.height) / 2 # 飞机y轴位置
self.is_running = True
def move_level(self, level):
# 防止飞机移出屏幕外, 增加判断
if 0 <= level <= SCREEN_WIDTH - self.rect.width:
self.rect.x = level
elif level < 0:
self.rect.x = 0
elif level > SCREEN_WIDTH - self.rect.width:
self.rect.x = SCREEN_WIDTH - self.rect.width
def move_vertical(self, vertical):
if 0 <= vertical <= SCREEN_HEIGHT - self.rect.height:
self.rect.y = vertical
elif vertical < 0:
self.rect.y = 0
elif vertical > SCREEN_HEIGHT - self.rect.height:
self.rect.y = SCREEN_HEIGHT - self.rect.height
class EnemyPlane(pygame.sprite.Sprite):
def __init__(self):
super(EnemyPlane, self).__init__()
self.image = pygame.image.load(os.path.join(IMG_PATH, "mp_show_3.png"))
self.rect = self.image.get_rect()
self.rect = self.image.get_rect()
self.rect.x = int(SCREEN_WIDTH - self.rect.width) # 飞机x轴位置
self.rect.y = int(SCREEN_HEIGHT - self.rect.height) / 2 # 飞机y轴位置
self.is_running = True
def main():
pygame.init()
# 初始化显示模块
pygame.display.init()
# 创建窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
# 设置窗口标题
pygame.display.set_caption("python小demo 飞机大战")
# 设置窗口icon
pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH, "icon.jpg")))
# 加载背景图片
background = pygame.image.load(os.path.join(IMG_PATH, "test_bj.png"))
# 初始化英雄
hero = HeroPlane()
# 初始化敌机
enemy = EnemyPlane()
# 加载背景音乐并播放
pygame.mixer.init()
pygame.mixer.music.load(os.path.join(MUSIC_PATH, "game_music.ogg"))
pygame.mixer.music.play(loops=-1)
def event_check():
"""
事件检测,这边做了一个简单的示例
return:
"""
global MOUSE_MOVE
for event in pygame.event.get():
if event.type == pygame.QUIT:
# 接收到退出事件后退出程序
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
MOUSE_MOVE = True
elif event.type == pygame.MOUSEBUTTONUP:
MOUSE_MOVE = False
if MOUSE_MOVE:
x, y = pygame.mouse.get_pos()
hero.move_level(x)
hero.move_vertical(y)
# def event_check():
# """
# 事件检测,这边做了一个简单的示例
# return:
# """
# # 设置KEYDOWN标志位,0代表键盘已释放,1、2、3、4分别代表⬅、⬆、⬇、➡
# global KEYDOWN
#
# for event in pygame.event.get():
# if event.type == pygame.QUIT:
# # 接收到退出事件后退出程序
# pygame.quit()
# sys.exit()
# elif event.type == pygame.KEYDOWN:
# if event.key == pygame.K_LEFT:
# KEYDOWN = 1
# elif event.key == pygame.K_UP:
# KEYDOWN = 2
# elif event.key == pygame.K_DOWN:
# KEYDOWN = 3
# elif event.key == pygame.K_RIGHT:
# KEYDOWN = 4
# elif event.type == pygame.KEYUP:
# KEYDOWN = 0
#
# if KEYDOWN:
# if KEYDOWN == 1:
# hero.move_level(hero.rect.x - 5)
# elif KEYDOWN == 2:
# hero.move_vertical(hero.rect.y - 5)
# elif KEYDOWN == 3:
# hero.move_vertical(hero.rect.y + 5)
# else:
# hero.move_level(hero.rect.x + 5)
def update_hero():
screen.blit(hero.image, (hero.rect.x, hero.rect.y))
def update_enemy():
screen.blit(enemy.image, (enemy.rect.x, enemy.rect.y))
def check_crash():
is_crash = pygame.sprite.collide_rect(hero, enemy)
if is_crash:
# 先展示飞机爆炸,然后在屏幕中间写下game over提示
screen.blit(pygame.image.load(os.path.join(IMG_PATH, "ex_2.png")), (hero.rect.x, hero.rect.y))
screen.blit(pygame.image.load(os.path.join(IMG_PATH, "ex_2.png")), (enemy.rect.x, enemy.rect.y))
pygame.mixer.Sound(os.path.join(MUSIC_PATH, "enemy1_down.wav")).play()
game_over = pygame.font.Font(None, 100)
game_over = game_over.render("game over", True, (220, 20, 60))
screen.blit(game_over, [int(SCREEN_WIDTH / 2 - game_over.get_width() / 2), int(SCREEN_HEIGHT / 2)])
while True:
# 事件检测
event_check()
# 将背景图片绘制到窗口上
screen.blit(background, (0, 0))
# 更新英雄在屏幕上的位置
update_hero()
# 更新敌机在屏幕上位置
update_enemy()
# 碰撞检测
check_crash()
# 更新屏幕上内容
pygame.display.update()
time.sleep(0.02)
if __name__ == "__main__":
main()
由于博客视频条件限制,这儿就不放效果了,感兴趣的朋友可以拉下我的代码体验下
所需函数简要说明
- pygame.mixer 用于加载和播放音频
mixer.init(
frequency=44100,
size=-16,
channels=2,
buffer=512,
devicename=None,
allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE | AUDIO_ALLOW_CHANNELS_CHANGE
) -> None
# 初始化mixer模块以进行声音加载和播放。可以重写默认参数以提供特定的音频混合
# 参数:
# frequency pygame 2.0.0+时,范围44100-22050
# size 表示每个音频样本使用了多少位。如果是负值,则使用带符号的样本值,无效值会触发异常,2.0.0后可以是32
# channels 指定使用单声道还是立体音,1为单声道,2为立体音, 2.0.0后可以是4或者6
# buffer 控制声音混合器mixer中使用的内部样本数,默认值应适用于大多数情况
# allowedchanges 当allowedchanges=0,将在运行时转换示例以匹配硬件支持的内容,allowedchanges也支持:
# AUDIO_ALLOW_FREQUENCY_CHANGE
# AUDIO_ALLOW_FORMAT_CHANGE
# AUDIO_ALLOW_CHANNELS_CHANGE
# AUDIO_ALLOW_ANY_CHANGE
mixer.music.load(filename) -> None
mixer.music.load(object) -> None
# 将加载音乐文件/或者音乐文件对象并准备播放,如果音乐已经播放,调用则会停止
mixer.music.play(loops=0, start=0.0, fade_ms = 0) -> None
# 播放已经加载的音乐流,如果已经在播放时调用,则会重新播放
# 参数:
# loops 可选整数参数,表示重复播放次数,设置为-1表示无限重复
# start 可选浮点数,表示开始播放音乐时间的位置,起始位置决定于音乐格式
# fade_ms 可选整数参数,大于0时,在给定的fade_ms内逐渐加大音量
pygame.mixer.Sound(filename) -> Sound
pygame.mixer.Sound(buffer) -> Sound
# 从文件或者缓冲区创建一个新的文件对象
pygame.mixer.Sound.play(loops=0, maxtime=0, fade_ms=0) -> Channel
# 开始在可用的频道上播放声音,播放时可能在必要时切断正在播放的声音
# 在本例中,调用该方法产生爆炸音效并不会影响背景音乐的播放
# 参数:
# loops 可选整数参数,表示重复播放次数,设置为-1表示无限重复
# maxtime 大于零时,在给定的maxtime停止播放(毫秒)
# fade_ms 可选整数参数,大于0时,在给定的fade_ms内逐渐加大音量
# 返回所选的通道对象
# 上面列举了本例需要的函数,更多使用方法可以点击上面文档链接查阅文档
python小demo 飞机大战完整例子
在上面,大致示范了使用pygame写一个飞机大战所需模块及函数,本人也写了一个示例,包括本推文中所使用的代码都提交至github,在公众号中回复“飞机大战”即可获取源码地址,及图片素材、音频素材,下面看下我例子图片: