Python编写游戏的环境搭建和编写过程已在上篇“Python编写游戏——拼图游戏”中进行了介绍,在此基础上本篇再介绍键盘控制、背景图像设置和音效设置。
一、开发工具
Python版本:Python 3.6.4或以上版本
二、相关模块:
pgzrun模块以及一些Python自带的标准模块。
三、环境搭建
在运行Python文件目录下建三个文件夹:images、fonts和music。背景图像、角色图像(默认是png格式)全部放在images文件夹、字库(默认为ttf字库)放在fonts文件夹、音效文件放在music文件夹中。
四、相关函数与方法
1.事件更新和绘图
绘图(draw())和更新(update())函数是相似的,更新(update())函数每秒会调用60次,而绘图(draw())函数只有在某些事情发生变化时才调用。
所以一般将变化多的:如键盘运动,球运动等放在更新(update())函数中,而背景图像、角色图像等放在绘图(draw())函数中。
1.设置背景色
screen.fill((R, G, B))
2.加载图像
screen.blit(图像, 坐标)
其中:图像默认为png图像,坐标为图像的topleft(即左上角,见图1)
图1 图像位置名称
3.鼠标与按键
游戏外部事件的触发控制on_xxx_xxx,pgzero提供了常用的鼠标和键盘事件:
键盘事件:on_key_down,on_key_up
鼠标事件:on_mouse_down,on_mouse_up,on_mouse_move
键盘的按键信息是通过keyboard内置对象获取的,鼠标是mouse来获取的,例如:
keyboard.a # 'a'键
keyboard.left # 向左箭头键
keyboard.rshift # 右侧shift键
keyboard.kp0 # 小键盘上的'0'键
keyboard.k_0 # 主键盘上的'0'键
mouse.left # 鼠标左键
mouse.right # 鼠标右键
mouse.middle # 鼠标中键(如果有的话)
也可以用key == keys.按键(按键用大写字母表示),例如:
if key == keys.LEFT:
player.x -= 5
4.音效
music.play_once(音乐)用于一次性播放“音乐”。音乐文件必须是存储在位于与游戏脚本相同位置的music文件夹,支持ogg、mp3格式,不支持wav格式。
5. colliderect()碰撞检测
colliderect()用于判断两个角色是否发生碰撞,如果发生碰撞返回True,没有发生碰撞返回False。
角色1.colliderect(角色2)
6.目录结构:
五、拼图游戏源代码
初始小球向上向左或向右移动,碰到玻璃块,玻璃块消失并发出击碎玻璃声音,向下移动时需要按左右箭头键移动击球棒将小球反弹回去,如果没有接住,当小球到达下边界时游戏结束。如果能够击碎所有玻璃块,你将赢得游戏。完整代码如下。
##############################################
# 设计 Zhang Ruilin 创建 2022-12-07 20:06 #
# 用 pgzrun 模块编制带音效的击球打玻璃块游戏 #
##############################################
import pgzrun
import random, sys
import time
TITLE = '击球打玻璃块'
WIDTH = 800
HEIGHT = 500
bat = Actor('bat') # 游戏角色1——击球棒
bat.x = 120
bat.y = 420
ball = Actor('ball') # 游戏角色2——球
ball.x = 30
ball.y = 300
bars_list=[]
ball_x_speed = 2*random.randint(0,1)-1
ball_y_speed = 1
gameover = False # 游戏结束标志(gameover=True结束游戏)
start = time.time() # 程序运行开始计时
newTime = 0 # 游戏计时所用秒数
st = 0 # 结束游戏计时
def draw():
global gameover, st
screen.blit('sky', (0,0)) # 绘制背景图
for bar in bars_list:
bar.draw()
bat.draw()
screen.draw.text('游戏运行:'+str(newTime)+'秒', (10, 10),
fontname='simkai', fontsize=15, color='yellow') # 楷体
screen.draw.text('还剩'+str(len(bars_list))+'块玻璃', (10, 30),
fontname='simkai', fontsize=15, color='yellow') # 楷体
if gameover:
ds = '您赢了!' if len(bars_list)==0 else '游戏结束!' # 玻璃块全击碎则赢
screen.draw.text(ds, center=(WIDTH/2, HEIGHT/2), # 居中显示
fontname='msyh.ttc',fontsize=50, color='orange') # 微软雅黑
if st == 0: st = time.time() # 结束游戏开始计时
ball.draw()
def place_bars(x,y,image):
bar_x = x
bar_y = y
for i in range(8):
bar = Actor(image)
bar.x = bar_x
bar.y = bar_y
bar_x += 90
bars_list.append(bar)
clrglassbar_list = ['glassbar_b', 'glassbar_g', 'glassbar_r'] # 三种颜色玻璃块
x = 88
y = 100
for clrglassbar in clrglassbar_list:
place_bars(x, y, clrglassbar)
y += 50
def update():
global ball_x_speed, ball_y_speed, gameover, newTime, st
if not gameover:
end = time.time()
newTime = int(end-start+0.5) # 更新程序运行时间(秒)
else:
if time.time() - st >=5: # 延时5秒退出系统
st = '您有'+str(len(bars_list))+'块玻璃没有击碎!'
sys.exit('您赢了!' if len(bars_list)==0 else st)
if keyboard.left: # 按向左键,向左移动击球棒
bat.x = bat.x - 5
if keyboard.right: # 按向右键,向右移动击球棒
bat.x = bat.x + 5
if keyboard.down: # 按向下键,降低球速
kx = 1 if ball_x_speed>0 else -1
ball_x_speed = kx*(abs(ball_x_speed)-1 if abs(ball_x_speed)>1 else 1)
ky = 1 if ball_y_speed>0 else -1
ball_y_speed = ky*(abs(ball_y_speed)-1 if abs(ball_y_speed)>1 else 1)
if keyboard.up: # 按向上键,增加球速
kx = 1 if ball_x_speed>0 else -1
ball_x_speed = kx*(abs(ball_x_speed)+1 if abs(ball_x_speed)<3 else 3)
ky = 1 if ball_y_speed>0 else -1
ball_y_speed = ky*(abs(ball_y_speed)+1 if abs(ball_y_speed)<3 else 3)
update_ball()
for bar in bars_list:
if ball.colliderect(bar): # 如果球遇到玻璃块
bars_list.remove(bar) # 删除此玻璃块
ball_y_speed *= -1 # 球改变上下移动方向
music.play_once('击碎玻璃.mp3') # 发出击碎玻璃音效
if len(bars_list) == 0: gameover = True # 如果玻璃块没有了赢得游戏
if bat.colliderect(ball): # 如果球遇到击球棒
ball_y_speed *= -1 # 球改变上下移动方向
rand = random.randint(0,1) # 击球时随机向左或向右反弹
if rand:
ball_x_speed *= -1
music.play_once('击球.mp3') # 发出击球音效
def update_ball():
global ball_x_speed, ball_y_speed, gameover
ball.x -= ball_x_speed
ball.y -= ball_y_speed
if (ball.x >= WIDTH-12) or (ball.x <=12): # 如果球遇到左右边界,反弹
ball_x_speed *= -1
if (ball.y <=12): # 如果球遇到上边界,反弹
ball_y_speed *= -1
if (ball.y >= HEIGHT-12): # 如果球遇到下边界
gameover = True # 没有击到球,游戏结束
pgzrun.go()
六、执行效果
图2 初始状态
图3 失败结束
图4 获胜结束