改造Cocos2d-x中的SimpleAudioEngine
背景
最近在制作一个音乐类的游戏, 很关键的一环就是需要谱表与音乐播放的时间贴合. 为了能得到游戏音乐的播放时间,按着能尽量不动引擎源码的方法, 比较直接有两种办法:
-
使用第三方库的游戏音效库, 如 FMOD
-
与此同时在Cocos2d-x 3.3的版本更新中也发提供了基于OpenAL的音频接口
cocos2d::experimental::AudioEngine
分析
这两种方法都有各自优缺点:
FMOD
优点:
-
功能强大, 如支持3D音乐音效
-
并不算困难的移植, 在CocoaChina2014秋季开发者大会中的Game audio made easy with FMOD Studio演讲中说了对Cocos2d-x的支持
缺点:
-
功能强大的反面就是学习成本的增加,而且游戏的在Cocos2d-js的框架下开发的, 所以还样做一层JSB, 所以为了两个API去实现这么多的集成成本有些大.
-
策划的学习成本的增加.
-
制作商业游戏的授权费用.
AudioEngine
在Cocos2d-x的版本更新中新加出的AudioEngine的类, 基于OpenAL进行实现, 在应该类中有实现了获取音乐时间和跳到某一时间的API. 优点就不说了, 只说不足:
-
虽然有了这样的API但是JSB里没有Binding, 需要自己手动添加.
-
精度不够, 使用getCurrentTime()时间精度只能达到0.1秒, 不足以支持节奏游戏的精度.(虽然可以调整精度, 但是经常会产生闪退的问题)
-
有Bug, 这个Bug在官方示例中也有, 就是当在播放音乐的时候接到了电话, 音乐永远不会再播放了, 除非杀掉程序.
-
莫名其妙的音乐实例会消失
解决办法
好吧, 只有改SimpleAudioEngine了, 经过实验, 音乐的时间精度可以达到需要的要求, 而且jsb也是没问题的
这个资料比较详细的介绍了SimpleAudioEngine的改造, 但是由于时间版本的问题这里的代码还是和实际工程中有些出入.所以还得修改一下(只针对IOS, Android可以自行扩展)
- SimpleAudioEngine.mm
static void static_setBackgroundMusicCurrentTime(float currentTime)
{
[[SimpleAudioEngine sharedEngine] setBackgroundMusicCurrentTime:currentTime];
}
static float static_getBackgroundMusicCurrentTime()
{
return [[SimpleAudioEngine sharedEngine] getBackgroundMusicCurrentTime];
}
float SimpleAudioEngine::getBackgroundMusicCurrentTime() {
return static_getBackgroundMusicCurrentTime();
}
void SimpleAudioEngine::setBackgroundMusicCurrentTime(float currentTime) {
static_setBackgroundMusicCurrentTime(currentTime);
}
- SimpleAudioEngine_objc.m
#pragma mark SimpleAudioEngine - setBackgroundMusicCurrentTime
-(void) setBackgroundMusicCurrentTime:(float) currentTime {
[am setBackgroundMusicCurrentTime:currentTime];
}
-(float) getBackgroundMusicCurrentTime{
return [am getBackgroundMusicCurrentTime];
}
- CDAudioManager.m
-(void) setBackgroundMusicCurrentTime:(float) currentTime {
[self.backgroundMusic.audioSourcePlayer setCurrentTime:currentTime];
}
-(float) getBackgroundMusicCurrentTime{
return self.backgroundMusic.audioSourcePlayer.currentTime;
}