You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
7.5 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 第15讲 | 如何载入背景音乐和音效?
好的音乐总是伴随着游戏一起,一直被玩家所记忆。在游戏中播放音乐和音效并不是什么困难的事情,但是究竟什么时候播放什么音效,具体怎么实现,这恐怕就需要一些技巧了。比如,我今天要讲的,我们可以和某些函数捆绑在一起实现。
Pygame支持mp3、ogg、wav音频和音效的播放。音乐的模块都在pygame.mixer中这里面包括音乐和音效。
我们在使用音频部分模块的时候,需要先初始化一次。
```
pygame.mixer.init()
```
这个初始化应该在pygame.init()的初始化之后。
我们来看一下具体的函数这些函数存在在pygame.mixer.Sound模块下。
![](https://static001.geekbang.org/resource/image/29/4d/299c0650d736f939189c49b32eb2b54d.jpg)
我们再来看一下Pygame.mixer.music音乐模块。我们可以尝试一下载入音频并且播放。
```
pygame.mixer.music.load('bgm.mp3')
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play()
s1 = pygame.mixer.Sound('a.wav')
s1.set_volume(0.5)
s2 = pygame.mixer.Sound('b.wav')
s2.set_volume(0.5)
```
我来解释一下这段代码。
刚开始我们载入了一个名叫bgm的mp3文件告诉程序需要载入这个文件然后调整音量到0.5随后就是play也就是播放播放是在程序的后台播放然后程序会接着跑到下面的代码行。
随后我们使用Sound模块Sound模块初始化会载入a.wav然后返回一个对象这个对象设置音量为0.5随后再初始化一次载入b.wav然后设置音量为0.5。
到这里为止,我们已经将所有的初始化、设置都在游戏的循环外做好了。
随后,我们需要结合前几节的内容,在循环里面,对飞机碰撞进行声音的操作,比如出现爆炸声的时候,播放什么声音;碰撞结束,播放另一种的声音。
```
if True == collide(pln, (100,300+y1), enm, (100,20+y2)):
s1.play()
else:
s2.play()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
if event.type == KEYDOWN:
if event.key == K_p:
pygame.mixer.music.pause()
if event.key == K_r:
pygame.mixer.music.unpause()
```
首先,我们使用**collide函数**。这在前面几章有过详细的说明。
这是一段检测飞机碰撞的代码如果飞机碰撞了的话就会返回True如果返回True的话我们就播放s1音频否则就播放s2音频。当然这个s2音频可能会一直在播放因为一直没有碰撞
随后就是**事件监测**如果检测到K\_p就是按下键盘p就让音乐停止使用pause函数如果按下r键就恢复播放。
我们在Pygame上的操作已经基本结束了但是音频和音效的内容并没有结束。
在游戏编程中我们需要嵌入音频和音效特别是在没有Pygame的时候如果有一些游戏引擎没有提供音频库的话我们就需要自己使用第三方的音频库。虽然可以使用耳熟能详的ffmpeg但是感觉有点大材小用了所以我们需要一个专门的音频库。
在这里,我推荐**BASS音频库**。你可以去 [http://www.un4seen.com](http://www.un4seen.com) 下载开发库。这个音频库是不开源的,如果你只是自己开发游戏玩玩,非商业目的,就可以使用。如果是商业使用,那就需要购买证书。
![](https://static001.geekbang.org/resource/image/90/e2/9022635f73854d8b464a188c585ee6e2.jpg)
在这个页面上我们点击download按钮就会下载最新版本的开发库。解压缩下来会出现对应几个语言的开发目录。
其中bass.dll文件是动态链接库要使用的话可以在c文件夹下使用lib库和bass.h进行头文件包含进行编程。
我们来看一下如何使用C/C++语言加入Bass引擎的代码。
```
BASS_Init(-1, 44100, 0, hwnd, NULL);
HSTREAM s = BASS_StreamCreateFile(false, "a.mp3", 0, 0, 0);
BASS_ChannelPlay(s, false);
BASS_StreamFree(s)
```
首先,我们将 BASS 库初始化初始化的参数是设备、输出比率、标志位比如8位音质、立体声、3D等等、Windows句柄。你也可以输入0。最后一个是clsid就是用于初始化DirectSound的类的ID一般会使用NULL。
随后开始从文件建立一个流BASS\_StreamCreateFile函数返回一个HSTREAM。HSTREAM其实是一个DWORD类型。
这个函数里的参数,我也解释一下。
* 第一个参数是内存。如果传入true的话就将这个流保存在内存中否则的话就不保存在内存中。
* 第二个参数是音频文件名。这个参数和第一个参数会联动。当第一个参数保存在内存中的时候,就填入内存地址,否则就填入文件名。
* 第三个参数是偏移量也就是文件从哪里开始播放。当然这个参数只在第一个参数为false不保存在内存的情况下起作用。
* 第四个参数是长度如果填入0就是所有长度。
* 最后一个是标志位,填入的是创建模式,比如是循环播放方式,还是软件解码模式等等。
接下来就是开始播放,第一个填入的是刚才返回的流的句柄,第二个参数是是否重新开始播放。最后一个就是播放完后进行回收资源,删除句柄。
```
float v; DWORD r;
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 100);
v = BASS_GetVolume();
v = 200;
BASS_SetVolume(v);
r = BASS_ChannelIsActive(s);
if(r == BASS_ACTIVE_PAUSED)
...
else if(r == BASS_ACTIVE_PLAYING)
...
else if(r == BASS_ACTIVE_STOPPED)
...
else if (r == BASS_ACTIVE_STALLED)
..
```
接下来就是调整音量以及获取播放的状态功能。
其中BASS\_SetConfig中第一个参数是选项第二个参数是调整音量的值BASS\_CONFIG\_GVOL\_STREAM的意义是全局的流的音量。
随后我们就开始取得音量BASS\_GetVolume是获取系统的音量并不是流的音量第五行代码就是设置系统音量。
接下来我们就要获取播放的状态。在BASS\_ChannelIsActive的函数内填入流的句柄随后获取返回值然后使用返回值进行比较其中BASS\_ACTIVE\_PAUSED就是播放状态暂停BASS\_ACTIVE\_PLAYING是正在播放中或者录音状态BASS\_ACTIVE\_STOPPED是停止状态或者流句柄并不是有效的BASS\_ACTIVE\_STALLED是停滞状态。
一般的原因是,播放的状态缺少样本数据,流的播放停滞了,如果数据足够播放的话,就会自动恢复。
BASS库还有许许多多的函数和功能就不在这里过多阐述了。
## 小结
我来总结一下。今天我们讲解了Pygame中音频和音效的播放。你应该记住这些东西。
* 在Pygame中播放音乐是不需要进行多线程控制的。它本身就会在后台进行播放。
* 所有的音乐和音效都在pygame.mixer模块中如果载入的是音乐就使用music模块如果载入的是音效就使用Sound模块。
* 随后我们介绍了BASS音频库。这几乎是最专业的音频库了。由于是C接口所以通用多种语言你可以使用.NET或者VB等语言来应用。当然如果要进行后台播放、多个频道播放等功能你需要编写多线程的代码并没有Pygame那么轻松这里面很多事情需要自己去做。
现在给你留一个小问题。
在pygame.mixer.music模块中如何播放一首音乐后立刻播放另外一首音乐
欢迎留言说出你的看法。我在下一节的挑战中等你!