文章目录
🚴大家好!我是近视的脚踏实地,虽然近视,但是脚踏实地,这一篇来学习游戏中的播放音乐和音效,然后继续完善未完成的小游戏
(一)概念
首先几乎没有什么游戏是一声不吭的,多重的感官体验更能刺激玩家的神经,没有声音的游戏就好比 不蘸番茄的薯条,忘记带枪的战士!
尽管如此,Pygame 对于声音的处理并不是太理想,我说的是如果你想用 Pygame 做一个炫酷的音乐播放器那可能会让你失望,因为Pygame对于声音格式的支持十分有限,不过对于游戏开发来说,这完全是足够的,我们需要的我们自己转换就可以了。
一般游戏来说,声音主要分为两种,一种是背景音乐,一种是音效。
背景音乐就是时刻伴随着游戏存在的,往往就是重复播放的一首曲子或者歌曲;
音效就是在某种条件下被触发产生的,比如飞机相撞会发出爆炸的声音
Pygame 支持的声音格式十分有限,一般情况下我们使用 .ogg 的格式来做背景音乐,用无压缩的 .wvb 来作为音效。
如果是拿到了一个 .mp3 格式,可以使用格式工厂这类的软件把它转为**.ogg** 或者 .wvb 格式,
还需要注意的是music 模块虽然写了支持 .mp3 格式,但是它对 .mp3 格式的支持十分有限,经常你会在网上找到一段很好的 .mp3 的曲子,但是载入之后压根没有声音。你把它转为 .ogg 格式就可以很好的支持了。
(二)播放声音和音效
1️⃣播放音效
—pygame.mixer.Sound()
播放音效我们使用 mixer 模块,在使用之前需要先生成一个Sound对象 ,对这个Sound对象进行控制,Sound 对象 的 play() 方法就是播放音效。
—Sound对象的方法
方法 | 含义 |
play() | 播放音效 |
stop() | 停止播放 |
fadeout() | 淡出 |
set_volume() | 设置音量 |
get_volume() | 获取音量 |
get_num_channels() | 计算该音效播放了多少次 |
get_length() | 获得该音效的长度 |
get_raw() | 将该音效以二进制格式的字符串返回 |
2️⃣播放背景音乐
—pygame.mixer.music
播放背景音乐我们使用 music 模块,music 模块和 mixer 模块是紧密关联的,所以我们用 .mixer.music 他是在mixer里边的
—music模块方法
方法 | 含义 |
load() | 载入音乐 |
play() | 播放音乐 |
rewind() | 重新播放 |
stop() | 停止播放 |
pause() | 暂停播放 |
unpause() | 恢复播放 |
fadeout() | 淡出 |
set_volume() | 设置音量 |
get_volume() | 获取音量 |
get_busy() | 检测音乐流是否正在播放 |
set_pos() | 设置开始播放的位置 |
get_pos() | 获取已经播放的时间 |
queue() | 将音乐文件放入待播放列表中 |
set_endevent() | 在音乐播放完毕时发送事件 |
get_endevent() | 获取音乐播放完毕时发送的事件类型 |
(三)小试牛刀
下面先来写个例子练练手,要求是打开程序就会自动播放背景音乐bg_music.ogg,然后当你在窗口中点击鼠标左键,就会播放 winner.wav 音效,当点击鼠标右键,就会播放 loser.wav 音效;点击空格键就暂停背景音乐,再次点击就继续播放。
import pygame
import sys
from pygame.locals import *
pygame.init()
pygame.mixer.init()
pygame.mixer.music.load("bg_music.ogg")
pygame.mixer.music.set_volume(0.2)
pygame.mixer.music.play()
winner_sound = pygame.mixer.Sound("winner.wav")
winner_sound.set_volume(0.2)
loser_sound = pygame.mixer.Sound("loser.wav")
loser_sound.set_volume(0.2)
bg_size = width,height = 300,200
screen = pygame.display.set_mode(bg_size)
pygame.display.set_caption("Music Monster Demo")
pause = False
pause_image = pygame.image.load("pause.png").convert_alpha()
unpause_image = pygame.image.load("unpause.png").convert_alpha()
pause_rect = pause_image.get_rect()
pause_rect.left,pause_rect.top = (width - pause_rect.width) // 2,(height - pause_rect.height) // 2
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
winner_sound.play()
if event.button == 3:
loser_sound.play()
if event.type == KEYDOWN:
if event.key == K_SPACE:
pause = not pause
screen.fill((255,255,255))
if pause:
screen.blit(pause_image,pause_rect)
pygame.mixer.music.pause()
else:
screen.blit(unpause_image,pause_rect)
pygame.mixer.music.unpause()
pygame.display.flip()
clock.tick(30)
代码解析:首先基本的流程是一样的,先导入相应的模块,初始化完pygame.init() ,接着先来初始化混音器模块 ,需要说明的是虽然上一个会把这个也初始化了,但是你最好确认一下,把这个也初始化好,这个不写一般不会有问题,但最好写上
接着就先来加载背景音乐,背景音乐是在mixer里面的music模块,pygame.mixer.music.load() ,音效的话可以同时播放多个,而music只能一次播放一个
接着pygame.mixer.music.set_volume(0.2) 就是来设置他的音量,
接着pygame.mixer.music.play() 表示开始播放.
接着来加载音效winner_sound = pygame.mixer.Sound(“winner.wav”) 就是实例化了一个Sound对象,传入文件的路径winner.wav
接着winner_sound.set_volume(0.2) 也来设置一下他的音量
下面就是把winner都改成loser 就好了
那接下来就和往常一样,做一个小窗口出来bg_size = width,height = 300 ,200 、screen = pygame.display.set_mode(bg_size)
接着来设置一下标题pygame.display.set_caption(“Music Monster Demo”)
接着pause = False 这是一个标志性的变量,表示是否点下了暂停,即当pause为True的时候就把music暂停一下,为False的时候就继续播放
接着来pause_image = pygame.image.load(“pause.png”).convert_alpha() 、unpause_image = pygame.image.load(“unpause.png”).convert_alpha() 加载一下播放和暂停的图片
接着来获取他们的矩形对象rect,等等可以放到窗口的正中央,正中央就是窗口的宽度减去图像的宽度再除以2,接着再来设置一下clock,不然的话cpu就会一直在运转,clock是我们在限制cpu不要跑太快,
接着进入到循环中,同样的,先来迭代存放事件的列表,其中if event.type == MOUSEBUTTONDOWN: 就是如果检测到了鼠标按钮按下事件,在里面在进行判断,如果是按下鼠标左键就1的时候,就播放winner.wav的音效,如果是3就loser.wav。
接着就是当键盘按下的事件就是KEYDOWN,然后去检测他的KEY,是不是按下了空格,那么就去把标准暂的pause变量来取反
接着来填充个纯白色的背景颜色就可以了, if pause: 然后根据pause的变量值来做不同的响应,pause为True就绘制一个暂定的按钮,就是那张图片screen.blit(pause_image,pause_rect) ,然后 pygame.mixer.music.pause() 调用这个方法让他暂停,后面类似
(四)把相应的背景音乐和音效加入到小游戏中
那么接下来就是把背景音乐放到小游戏中,直接拷贝上一篇博客的最后一份代码来添加就可以了
import pygame
import sys
from pygame.locals import *
from random import *
# 球类继承自Spirte类
class Ball(pygame.sprite.Sprite):
def __init__(self, image, position, speed, bg_size):
# 初始化动画精灵
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image).convert_alpha()
self.rect = self.image.get_rect()
# 将小球放在指定位置
self.rect.left, self.rect.top = position
self.speed = speed
self.width, self.height = bg_size[0], bg_size[1]
self.radius = self.rect.width / 2
def move(self):
self.rect = self.rect.move(self.speed)
# 如果小球的左侧出了边界,那么将小球左侧的位置改为右侧的边界
# 这样便实现了从左边进入,右边出来的效果
if self.rect.right < 0:
self.rect.left = self.width
elif self.rect.left > self.width:
self.rect.right = 0
elif self.rect.bottom < 0:
self.rect.top = self.height
elif self.rect.top > self.height:
self.rect.bottom = 0
def main():
pygame.init()
ball_image = "gray_ball.png"
bg_image = "background.png"
running = True
# 添加魔性的背景音乐
pygame.mixer.music.load("bg_music.ogg")
pygame.mixer.music.play()
# 添加音效
loser_sound =pygame.mixer.Sound("loser.wav")
laugh_sound =pygame.mixer.Sound("laugh.wav")
winner_sound = pygame.mixer.Sound("winner.wav")
hole_sound = pygame.mixer.Sound("hole.wav")
#音乐播放完时游戏结束
GAMEOVER = USEREVENT
pygame.mixer.music.set_endevent(GAMEOVER)
# 根据背景图片指定游戏界面尺寸
bg_size = width, height = 1024, 681
screen = pygame.display.set_mode(bg_size)
pygame.display.set_caption("Play the ball - Monster ZF")
background = pygame.image.load(bg_image).convert_alpha()
# 用来存放小球对象的列表
balls = []
group = pygame.sprite.Group()
# 创建五个小球
for i in range(5):
# 位置随机,速度随机
position = randint(0, width-100), randint(0, height-100)
speed = [randint(-10, 10), randint(-10, 10)]
ball = Ball(ball_image, position, speed, bg_size)
while pygame.sprite.spritecollide(ball, group, False, pygame.sprite.collide_circle):
ball.rect.left, ball.rect.top = randint(0, width-100), randint(0, height-100)
balls.append(ball)
group.add(ball)
clock = pygame.time.Clock()
while running:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 游戏失败
elif event.type == GAMEOVER:
loser_sound.play()
pygame.time.delay(2000)
laugh_sound.play()
running = False
screen.blit(background, (0, 0))
for each in balls:
each.move()
screen.blit(each.image, each.rect)
for each in group:
group.remove(each)
if pygame.sprite.spritecollide(each, group, False, pygame.sprite.collide_circle):
each.speed[0] = -each.speed[0]
each.speed[1] = -each.speed[1]
group.add(each)
pygame.display.flip()
clock.tick(30)
if __name__ == "__main__":
main()
代码解析,那么就是在main方法里先来加载背景音乐pygame.mixer.music.load(“bg_music.ogg”) 然后播放pygame.mixer.music.play()
接下来添加音效,那么就是如果游戏成功的话,就是在背景音乐播放完之前,把5个球全部填到坑里,那么他会播放winner.wav胜利者的声音,然后隔两秒之后会播放laugh.wav 大笑的声音,然后如果输的话,就会播放loser.wav的声音,然后播放大笑声,还有就是hole.wav 就是球进洞的时候播放这个音效,那么把他们一个一个载入就好
那么音效呢只要在需要的时候调用它的play() 方法,例如上面说的各种情况,而背景音乐呢我们希望他贯穿游戏的始终,背景音乐完整播放一次,我们视为游戏的时间,因此接下来我们要想办法让游戏在背景音乐停止时结束,同时游戏
刚刚在上面的学习中可以看到music模块有个set_endevent() 方法,这个方法的作用就是在音乐播放完之后发送一条事件消息,那发送什么消息,这是我们自定义的,之前讲事件的时候,讲到了userevent用户自定义消息,pygame为我们预定了很多默认的事件,像我们熟悉的键盘事件,鼠标事件啊,之前我们都在用
那么对于这些预定义的事件都有一个标志符,像MOUSEBUTTONDOWN、MOUSEBUTTONUP、KEYUP、KEYDOWN,其实这些都是一些数字的等值定义,就是为了方便我们人类理解才作定义的,他在后背他就是一个数字,比如说2表示鼠标按下,但是我们看到2我们很难去记住2是什么事件,3是什么事件,所以他把他定义为KEYDOWN,KEYUP。这样人类就很容易理解了。
USEREVENT以上则是我们自定义的事件,USEREVENT是个数字,应该是24,24以上就是我们可以自定义的事件,那么我们可以像这样来定义事件MYEVENT == USEREVENT、MYEVENT2 == USEREVENT+1、MYEVENT2== USEREVENT+2
那么有了上面的知识我们就可以让我们的背景音乐播放完之后游戏结束的时候,播放失败者的声音,并且大笑,
那么就是当音乐播放完之后,pygame.mixer.music.set_endevent(GAMEOVER) 就会发一个GAMEOVER这个事件发送到事件的消息,队列里边去,然后就去事件那里检测,检测到GAMEOVER事件就处理,如下:👇
本篇博客到这就完啦,下一篇继续完善这个小游戏,非常感谢您的阅读🙏,如果对您有帮助,可以帮忙点个赞或者来波关注鼓励一下喔😬 ,嘿嘿👀