经过前面的介绍,读者应该认识到在游戏当中背景音乐与声音特效的区别。虽然它们都属于声音,但是却享受了引擎不同的服务。接下来,将通过一个示例程序为读者展示两者的用法。此时,读者事先准备的声音文件,就能派上用场了。
背景音乐通常是贯穿整个游戏的一段声音效果。因为它需要体现游戏的风格,所以开发者都会为游戏制作一段音频文件。一段优秀的背景音乐甚至会成为游戏代表性的标志。
声音效果通常是表现游戏效果的一段短暂声音。音效会作为游戏表达的辅助途径,其中大多是按键、爆炸、砍杀,针对特定的游戏内容。
无论是背景音乐,还是声音效果,在介绍代码函数时,都存在一个预先加载的函数。这样做的好处就是提前将声音资源加载入内存。当游戏播放声音时,减少延时。先来看看示例项目CocosDenshionTest中预先加载的内容,见代码8-3。
代码8-3 预加载声音资源
//音效文件 //Android平台只支持OGG的音效格式 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #define EFFECT_FILE "effect2.ogg" #elif( CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE) #define EFFECT_FILE "effect1.raw" #else #define EFFECT_FILE "effect1.wav" #endif // CC_PLATFORM_ANDROID //背景音乐文件 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) #define MUSIC_FILE "music.mid" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_BLACKBERRY) #define MUSIC_FILE "background.ogg" #else #define MUSIC_FILE "background.mp3" #endif // CC_PLATFORM_WIN32 //预加载背景音乐和音效文件 SimpleAudioEngine::getInstance()->preloadBackgroundMusic( FileUtils ::getInstance()->fullPathFromRelativeFile(MUSIC_FILE) ); SimpleAudioEngine::getInstance()->preloadEffect( FileUtils ::getInstance()->fullPathFromRelativeFile(EFFECT_FILE) ); //设置音量大小 SimpleAudioEngine::getInstance()->setEffectsVolume(0.5); SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(0.5);
不同的平台需要使用不同的声音文件格式。这是跨平台引擎的一个特点。因此在代码8-3中,针对不同平台,通过宏定义的方式来选择声音文件。在定义了游戏中音乐与音效的文件之后,就可以调用预加载函数,将声音资源提前加载。代码中只是加载了一个音乐文件和一个音效文件。预加载的函数在各个平台都有独自的实现方法。
注意:预加载函数在每个平台的实现代码不同。声音文件不一定都会提前加载至内存当中。
比如在Win32平台中,由于PC机加载声音文件的速度非常快,就算在播放之前,立即加载也不会出现延迟,因此就没有必要事先占用内存空间了。
在很多平台中,可以支持预加载多个音效文件。例如Android和iOS就支持多个音效加载。同时,在一些平台中,背景音乐与音效文件采用了不同的声音库来处理。比如在Android平台,背景音乐是用了MediaPlayer库,而音效的操作则是用了OpenSL库。大多数平台支持一个背景音乐的操作,也就是只能够预加载一个声音资源。
因为采用了外观模式,所以开发者无需关注声音实现的细节,读者只需调用简单的接口就可以实现声音功能。但是当读者要制作一款音乐类型的游戏时,为了向玩家展现更好的效果,就不得不根据各个平台的特性来优化。下面代码8-4是示例程序中声音函数的调用部分。这些内容只适用通常的游戏。
代码8-4
void CocosDenshionTest::menuCallback(Ref * pSender) { //得到用户选择的按钮 MenuItem* pMenuItem = (MenuItem *)(pSender); int nIdx = pMenuItem->getZOrder() - 10000; //判断用户操作,执行功能 switch(nIdx) { //播放背景音乐 case 0: SimpleAudioEngine::getInstance()->playBackgroundMusic(std::string(FileUtils :: getInstance()->fullPathFromRelativeFile(MUSIC_FILE)).c_str(), true); break; //停止背景音乐 case 1: SimpleAudioEngine::getInstance()->stopBackgroundMusic(); break; // 暂停背景音乐 case 2: SimpleAudioEngine::getInstance()->pauseBackgroundMusic(); break; // 恢复背景音乐 case 3: SimpleAudioEngine::getInstance()->resumeBackgroundMusic(); break; // 回放背景音乐 case 4: SimpleAudioEngine::getInstance()->rewindBackgroundMusic(); break; // 判断背景音乐是否播放 case 5: if (SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying()) { CCLOG("background music is playing"); } else { CCLOG("background music is not playing"); } break; //播放音效 case 6: m_nSoundId = SimpleAudioEngine::getInstance()->playEffect(std::string(FileUtils :: getInstance()->fullPathFromRelativeFile(EFFECT_FILE)).c_str()); break; // 循环播放音效 case 7: m_nSoundId = SimpleAudioEngine::getInstance()->playEffect(std::string(FileUtils :: getInstance()->fullPathFromRelativeFile(EFFECT_FILE)).c_str(), true); break; // 停止音效 case 8: SimpleAudioEngine::getInstance()->stopEffect(m_nSoundId); break; // 清除音效 case 9: SimpleAudioEngine::getInstance()->unloadEffect(std::string(FileUtils :: getInstance()->fullPathFromRelativeFile(EFFECT_FILE)).c_str()); break; // 加大背景音乐的音量 case 10: SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(SimpleAudioEngine:: getInstance()->getBackgroundMusicVolume() + 0.1f); break; // 减小背景音乐的音量 case 11: SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(SimpleAudioEngine:: getInstance()->getBackgroundMusicVolume() - 0.1f); break; // 加大音效的音量 case 12: SimpleAudioEngine::getInstance()->setEffectsVolume(SimpleAudioEngine::getInstance()-> getEffectsVolume() + 0.1f); break; // 减小音效的音量 case 13: SimpleAudioEngine::getInstance()->setEffectsVolume(SimpleAudioEngine::getInstance()-> getEffectsVolume() - 0.1f); break; //暂停音效 case 14: SimpleAudioEngine::getInstance()->pauseEffect(m_nSoundId); break; //恢复音效 case 15: SimpleAudioEngine::getInstance()->resumeEffect(m_nSoundId); break; //暂停所有音效 case 16: SimpleAudioEngine::getInstance()->pauseAllEffects(); break; //恢复所有音效 case 17: SimpleAudioEngine::getInstance()->resumeAllEffects(); break; //停止所有音效 case 18: SimpleAudioEngine::getInstance()->stopAllEffects(); break; } }
因为类SimpleAudioEngine的简化作用,所以所有的声音功能只需要一个函数就可以完成。并且由于采用了单例模式,读者可以在游戏代码中的任何地方调用声音的函数。声音模块已经设计成如此简单易用的方式了,实在是无需更多讲解了。读者可以马上动手为游戏加入音乐和音效了。