前言
基础模块的知识通过这么长时间的学习已经有所了解,更加深入的话需要通过完成各种项目,在这个过程中逐渐学习,成长。
我们的下一步目标是完成python crash course中的外星人入侵项目,这是一个2D游戏项目。在这之前,我们先简单学习一下pygame模块。
私信我发送消息python资料,领取python crash course中文版PDF。
pygame
Pygame是一个开源的Python多媒体开发库,专门用于开发2D游戏。它是Python编程语言的一个扩展,基于 SDL (Simple DirectMedia Layer) 库,提供了丰富的功能来处理图形、声音、事件处理等游戏开发所需的基本要素,使得创建游戏变得更加简单直接。
事件处理
在pygame中,事件监听是游戏开发中非常关键的一部分,它允许你响应用户的输入和其他系统事件。
pygame使用一个事件队列来管理所有事件,这个队列包含了自从上一次检查以来发生的每一个事件。
# 点击关闭退出程序,这个后面再讲,代码可以先写上。
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
这块代码大家眼熟不眼熟,基本上我们之前学习的模块中最后都以这个结尾,在窗口那一节的时候也简单讲过这段代码的作用,就是监听事件,假如事件类型是退出的话,调用pygame.quit()退出并清理pygame资源,exit()退出Python程序。
上面的代码就是最简单的事件监听。
接下来我们再仔细讲讲事件监听处理。
获取事件
每次游戏循环迭代时,通常会调用pygame.event.get()来获取并处理这些事件。没循环一次,我们就会根据监听的事件进行处理,根据预定的业务进行响应。
事件类型
我们通常根据事件的类型来判定我们需要响应的业务,并通过编写代码完成业务。
在pygame中,包含以下常用的类型:
- pygame.QUIT: 当用户关闭窗口时触发。
- pygame.KEYDOWN 和 pygame.KEYUP: 分别在按键按下和释放时触发。
- pygame.MOUSEBUTTONDOWN, pygame.MOUSEBUTTONUP, pygame.MOUSEMOTION: 分别在鼠标按钮按下、释放和鼠标移动时触发。
这个几个类型,大家一看就知道能干嘛。这里就简单讲一下。
其实就是对常用操作的一些归纳,方便我们进行响应。比如我们监听到这次的事件类型是QUIT,业务代码就是清理资源,退出程序。
按键按下和鼠标按下移动都需要结合事件的属性,获取到确定的属性值后进行对应的业务处理。
比如按钮按下,我们需要根据属性值,获取按下的键是哪个,如果是空格,我们可以编写音乐暂停,游戏暂停的业务代码,假如是上下左右键,我们可以编写上一首下一首音量加减或者游戏人物前后左右移动的业务代码。
比如鼠标按下,我们同样根据属性值获取鼠标按下位置的坐标,假入是任务,进行人物对话触发的业务代码编写,假如是空白的地方,无响应或者进行人物移动的业务代码编写。
事件属性
获取事件属性 每个事件都有特定的属性,如event.pos可以获取鼠标事件的位置,event.key可以获取按键事件的键值。
事件队列清理
在处理完所有事件后,pygame.event.get()会自动从队列中移除已经处理过的事件。如果不需要处理某些类型的事件,可以传递事件类型作为参数给pygame.event.get()来过滤它们。
自定义事件
除了标准事件,你还可以定义自己的事件,使用pygame.USEREVENT加上一个整数来标识。
等待事件
如果你想让程序暂停直到某个事件发生,可以使用pygame.event.wait()。
代码示例
暂停播放与继续播放
接下来,我们通过代码来实现音乐的播放与暂停。
import pygame
pygame.init()
pygame.mixer.init()
# 没啥用的窗口,单纯为了关闭窗口退出音乐播放
screen = pygame.display.set_mode((1200, 800))
# 加载音乐
pygame.mixer.music.load('../day21/叶倩文 - 情人知己.wav')
# 播放
pygame.mixer.music.play()
# 控制音乐播放状态的变量,根据这个状态判定按空格时是要继续播放还是暂停播放
paused = True
# 点击关闭退出程序,这个后面再讲,代码可以先写上。
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# 如果是播放状态
if paused:
# 播放状态按空格,说明要暂停播放
pygame.mixer.music.unpause()
# 设置播放状态为False,表示当前处于暂停状态
paused = False
# 不是播放状态那就是暂停状态
else:
# 暂停状态按空格,表示要继续播放
pygame.mixer.music.pause()
# 设置播放状态为True,表示当前处于播放状态
paused = True
这里和后面的截图就不贴了,没啥用就一个窗口。
代码注释已经写的很详细了,这里稍微再讲一下。
实现上述功能,主要是想清楚实现业务的逻辑思维。前面的都是之前学过的基础代码,开窗口,加载音乐和播放都很简单,重点在于暂停播放暂停播放的连续性的处理。代码中我们通过一个状态标识来判定当前按下空格应该暂停还是继续播放,并且每次响应都要对应修改标识变量的值,如果想不明白, 仔细再想!还想不明白,私信我!
切歌
切歌其实就是识别按键的值是不是←
和→
就行,当然还要注意的是music模块没有提供上一首下一首的功能,我们需要特殊处理才能实现。
import pygame
pygame.init()
pygame.mixer.init()
# 没啥用的窗口,单纯为了关闭窗口退出音乐播放
screen = pygame.display.set_mode((1200, 800))
# 定义播放列表
playlist = [
'../day21/叶倩文 - 情人知己.wav',
'../day21/容祖儿-小小.wav'
]
# 初始化播放列表的索引
current_song_index = 0
# 加载音乐
pygame.mixer.music.load(playlist[current_song_index])
# 播放
pygame.mixer.music.play()
# 控制音乐播放状态的变量,根据这个状态判定按空格时是要继续播放还是暂停播放
paused = True
# 点击关闭退出程序,这个后面再讲,代码可以先写上。
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# 如果是播放状态
if paused:
# 播放状态按空格,说明要暂停播放
pygame.mixer.music.unpause()
# 设置播放状态为False,表示当前处于暂停状态
paused = False
# 不是播放状态那就是暂停状态
else:
# 暂停状态按空格,表示要继续播放
pygame.mixer.music.pause()
# 设置播放状态为True,表示当前处于播放状态
paused = True
elif event.key == pygame.K_RIGHT:
# 按右键,需要切下一首歌,所以需要将当前索引加一
# 为什么要取模呢?因为播放列表的长度是有限,为了能够列表循环播放,我们需要对列表进行取模
# 所以这段代码的执行结果如下:(0 + 1) % 2 = 1对应小小 (1 + 1) % 2 = 0对应情人知己 (1 + 1) % 2 (2 + 1) % 2 (3 + 1) % 2
current_song_index = (current_song_index + 1) % len(playlist)
pygame.mixer.music.load(playlist[current_song_index])
pygame.mixer.music.play()
elif event.key == pygame.K_LEFT:
# 按左键,需要切上一首歌,所以需要将当前索引减一
# 唯一特殊的就是当current_song_index为0时,是负数的取模运算
current_song_index = (current_song_index - 1) % len(playlist)
pygame.mixer.music.load(playlist[current_song_index])
pygame.mixer.music.play()
因为music模块不提供切歌功能,我们需要自己编写代码模拟实现。
那么怎么模拟呢?我们切歌其实就是修改模块加载歌曲的路径,那么是不是把这些路径放在一起,有一定的顺序,通过某种方式可以自由的获取到这些值。
这个时候我们的目标就是可以任意访问一堆有序值里面的某个我们想要访问值。那么列表是不是很明显符合我们的要求?
我们创建了一个列表,存在歌曲路径,并且定义了一个变量作为歌曲路径的索引。我们按下←
和→
按钮就对索引值就行修改,索引值一修改,加载的路径也就跟着修改了。这个时候我们就会编写出以下代码:
--snip--
# 定义播放列表
playlist = [
'../day21/叶倩文 - 情人知己.wav',
'../day21/容祖儿-小小.wav'
]
# 初始化播放列表的索引
current_song_index = 0
--snip--
elif event.key == pygame.K_RIGHT:
current_song_index = current_song_index + 1
pygame.mixer.music.load(playlist[current_song_index])
pygame.mixer.music.play()
elif event.key == pygame.K_LEFT:
current_song_index = current_song_index - 1
pygame.mixer.music.load(playlist[current_song_index])
pygame.mixer.music.play()
这个时候你又发现,我一直按←
或者→
,索引值会不停的变大或变小,但是列表长度是有限的,那怎么办?
这个时候你的目标是什么呢? 索引值要限制在列表大小内,大于等于0。那么取模运算是不是很符合要求。 我们只要将索引值与列表长度进行取模运算,结果是不是就是0-(len-1)的范围内,正好是列表索引值的取值范围。
那么这个时候代码就变成下面这个样子:
--snip--
elif event.key == pygame.K_RIGHT:
current_song_index = (current_song_index + 1) % len(playlist)
pygame.mixer.music.load(playlist[current_song_index])
pygame.mixer.music.play()
elif event.key == pygame.K_LEFT:
current_song_index = (current_song_index - 1) % len(playlist)
pygame.mixer.music.load(playlist[current_song_index])
pygame.mixer.music.play()
当然,这也就是我们的终极版本了。 这个时候,我们运行代码,已经可以通过←
和→
可以自由切歌,并且是在列表内循环的切歌,同时也可以通过空格来暂停和继续播放音频。
结尾
事件的监听目前就讲到了这里,文章中用歌曲的播放切歌功能,验证了事件类型为按键按下的业务处理。按键弹起的类型,通常用于长按的场景,比如音量加减,按一下加一点,长按一直加,按键弹起停止加减。这个场景的代码放在作业里自行编写,写不出或者有问题可以四私信我。
鼠标相关的事件类型明后两天看一下,能不能更出来,通过按键切歌调节音量暂停这些,同时制作几个按钮通过鼠标点击来切歌调节音量暂停这些。因为是临时写,也没有去找素材啥的,所以是在窗口实现一个简陋的播放器的功能。
因为我也是在自学,我进度几乎是平齐的,以前一天两更,现在只有一更也是因为进度赶不上。
另外的话按键的值也不止这几个,大家在编写代码的时候可以找找看其他值的使用,后面我会单独出一份对照表供大家参考。
作业
- 监听ygame.KEYDOWN 和 pygame.KEYUP两种事件类型,通过按键
↑
和↓
调节音频的音量。