这节课我们来谈谈 Pygame 中的 播放声音和音效,因为几乎没有任何游戏是一声不吭的,多重的感官体验更能刺激玩家的神经,没有声音的游戏就好比 不蘸番茄的薯条,尽管如此,Pygame 对于声音的处理并不是太理想,我说的是如果你想用 Pygame 做一个炫酷的音乐播放器那可能会让你失望,因为Pygame对于声音格式的支持十分有限,不过对于游戏开发来说,这完全是足够的,我们需要的我们自己转换就可以了。

一般游戏来说,声音主要分为两种,一种是背景音乐,一种是音效。

背景音乐就是时刻伴随着游戏存在的,往往就是重复播放的一首曲子或者歌曲;音效就是在某种条件下被触发产生的,比如两个小球碰撞在一起就会发出 "啪啪啪" 的声音。

刚才我们也说了,Pygame 支持的声音格式十分有限,一般情况下我们使用 .ogg 的格式来做背景音乐,用无压缩的 .wvb 来作为音效。那么你拿到一个 .mp3 格式该怎么办呢?

你可以使用 格式工厂 这类的软件把它转为 .ogg 或者 .wvb 格式。

注意:music 模块虽然写了支持  .mp3  格式,但是它对 .mp3 格式的支持十分有限,经常你会在网上找到一段很好的 .mp3 的曲子,但是载入之后压根没有声音。你把它转为 .ogg 格式就可以很好的支持了。

 

•播放音效:

–pygame.mixer.Sound()

播放音效我们使用 mixer 模块,在使用之前,需要先生成一个 Sound 对象,对这个 Sound 对象进行控制,Sound 对象 的 play() 方法就是播放音效,稍候我们来讲这些方法。

•播放背景音乐:

–pygame.mixer.music

播放背景音乐我们使用 music 模块,music 模块和 mixer 模块是紧密关联的。

Sound 对象方法如下:

方法

含义

play()

播放音效

stop()

停止播放

fadeout()

淡出

set_volume()

设置音量

get_volume()

获取音量

get_num_channels()

计算该音效播放了多少次

get_length()

获得该音效的长度

get_raw()

将该音效以二进制格式的字符串返回

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 音效;点击空格键就暂停背景音乐,再次点击就继续播放。(需要这几个声音文件的的可以在下面评论区留下邮箱,我看到后就把免费发送给你们)

python音频变速 python 音效_音乐播放

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 - Python 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:
            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)#帧率

python音频变速 python 音效_python音频变速_02

python音频变速 python 音效_Python_03

上面就是我们实现 music 模块的 Demo。

现在我们就来把我们学到的新东西加到 Play TheBall 小游戏中。我们继续完善我们的代码:

代码如下:(需要素材的可以在评论区留下邮箱)

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.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)
    laugh_sound = pygame.mixer.Sound("laugh.wav")
    laugh_sound.set_volume(0.2)
    hole_sound = pygame.mixer.Sound("hole.wav")
    hole_sound.set_volume(0.2)

    #背景音乐会贯穿游戏的始终,背景音乐完整播放一次我们视为游戏的时间,
    #因此我们需要想办法让游戏在背景音乐停止时结束,我们应该有留意到:
    #music 模块有一个 set_endevent() 方法,该方法的作用就是在音乐播放完时
    #发送一条事件消息,发送什么消息是我们自定义的,USEREVENT 就是自定义消息,
    #Pygame 给我们预定了很多事件,像我们熟悉的 键盘事件、鼠标事件等。这些预定义
    #的事件都有一个标记符,例如:MOUSEBUTTONDOWN 、KEYDOWN等。这些都是
    #一些数字的等值定义,其实在内部,2 就表示鼠标按下,但是人类难以记住,所以定义为
    #MOUSEBUTTONDOWN。
    #USEREVENT 就是数字24,24以上就是我们可以自定义的事件,我们可以像这样自定义事件:
    # MY_EVENT = USEREVENT。
    # MY_EVENT_1 = USEREVENT + 1........
    
    #音乐播放完时,游戏结束
    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 - Python Demo")

    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:
                sys.exit()

            #####################################################################
            elif event.type == GAMEOVER: #判断事件是否为我们自定义的GAMEOVER事件
                loser_sound.play()  
                pygame.time.delay(2000)#暂停2秒
                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()

有一点需要讲解的:

背景音乐会贯穿游戏的始终,背景音乐完整播放一次我们视为游戏的时间,因此我们需要想办法让游戏在背景音乐停止时结束,我们应该有留意到:

music 模块有一个 set_endevent() 方法,该方法的作用就是在音乐播放完时发送一条事件消息,发送什么消息是我们自定义的,USEREVENT 就是自定义消息,Pygame 给我们预定了很多事件,像我们熟悉的 键盘事件、鼠标事件等。这些预定义的事件都有一个标记符,

例如:MOUSEBUTTONDOWN 、KEYDOWN等。这些都是一些数字的等值定义,其实在内部,2 就表示鼠标按下,但是人类难以记住,所以定义为    MOUSEBUTTONDOWN。

USEREVENT 就是数字24,24以上就是我们可以自定义的事件,我们可以像这样自定义事件:

     MY_EVENT = USEREVENT。

     MY_EVENT_1 = USEREVENT + 1........