在以前的博文中,我们已经讲解了AVAudioPlayer和SystemSoundService的用法。这两种功能在一定程度上都适合作为游戏音效的播放方式。而两者也各有其优缺点。下面我们来总结一下有哪些:
1)AVAudioPlayer的优点
(1)可以播放任意长度音乐;
(2)可以循环播放;
(3)可以控制播放的时间;
(4)可以控制声道的音量实现立体声效果;
(5)可以调整音量。
2)AVAudioPlayer的缺点
(1)播放之前必须先加载,不能立即播放;
(2)一次一个AudioPlayer只能播放所加载的音乐,不能同时播放好几次同样的音乐。
(3)没有振动效果
3)SystemSoundService的优点:
(1)能够立即播放
(2)能够在同一时间播放多次音乐
(3)可以加上振动效果
4)SystemSoundService的缺点:
(1)不能循环播放
(2)不能控制播放时间
(3)不能控制声道
(4)不能控制音量
(5)不能暂停音乐
我们发现,这两种音乐播放方式的优缺点几乎是完全互补的。那么,有什么用呢?
关键:我们这里考虑的是游戏音效的播放!都是短时间的音频播放!
想象一下游戏,有时候我们要重复的播放一个音效,有时候我们想来一个振动,有时候我们需要在短时间内播放同一个音频多次!
因此,我们可以考虑综合两者的功能!
办法:
利用AVAudioPlayer来实现SystemSoundService的效果!弥补AVAudioPlayer的缺点
我们先明确一下我们需要的功能:
(1)初始化后即可立即播放
(2)能在一个时间段内播放同一音频多次。这个再做个详细说明:我们使用AVAudioPlayer时,play后必须等其停止了才能重新播放。我们这里要改进的是即使前面的播放还没有结束,我们也可以启动新的播放,这个特别适用于播放敲击的声音,这样我们会感觉听到多个敲击的声音,而不是只有一个。记住这里不是讲和其他的AVAudioPlayer混音。
(3)能循环播放
(4)能暂停停止播放
(5)能播放震动和播放音频并震动
(6)能调节声道
(7)能调节音量
下面我们通过新建一个自定义的类来实现。
下面是头文件的代码:
#import <AVFoundation/AVFoundation.h> #import <AudioToolbox/AudioToolbox.h> @interface SRAudioPlayer : NSObject { AVAudioPlayer *_audioPlayer1; AVAudioPlayer *_audioPlayer2; } @property (nonatomic,assign) float pan; // 调节声道平衡 @property (nonatomic,assign) float volume; // 调节音量 // 初始化 - (id)initWithContentsOfURL:(NSURL *)URL error:(NSError *__autoreleasing *)outError; // 播放一次 - (void)playOnce; // 循环播放 - (void)playInfinite; // 播放并震动 - (void)playOnceWithVibrate; - (void)pause; - (void)stop; // 振动 - (void)vibrate; @end
下面是m文件的代码:
#import "SRAudioPlayer.h" @implementation SRAudioPlayer{ BOOL _isPlayingAudioPlayer1; } - (id)initWithContentsOfURL:(NSURL *)URL error:(NSError *__autoreleasing *)outError { if ((self = [super init])) { _audioPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:outError]; _audioPlayer2 = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:outError]; [_audioPlayer1 prepareToPlay]; [_audioPlayer2 prepareToPlay]; } return self; } - (void)setPan:(float)pan { if (_pan != pan) { _pan = pan; _audioPlayer1.pan = pan; _audioPlayer2.pan = pan; } } - (void)setVolume:(float)volume { if (_volume != volume) { _volume = volume; _audioPlayer1.volume = volume; _audioPlayer2.volume = volume; } } - (void)playOnce { _audioPlayer1.numberOfLoops = 1; if (!_isPlayingAudioPlayer1) { if (!_audioPlayer1.isPlaying) [_audioPlayer1 play]; else _audioPlayer1.currentTime = 0.0f; _isPlayingAudioPlayer1 = YES; } else { if (!_audioPlayer2.isPlaying)[_audioPlayer2 play]; else _audioPlayer2.currentTime = 0.0f; _isPlayingAudioPlayer1 = NO; } } - (void)playInfinite { [_audioPlayer2 pause]; _audioPlayer1.currentTime = 0.0f; _audioPlayer1.numberOfLoops = -1; } - (void)playOnceWithVibrate //1 { _audioPlayer1.numberOfLoops = 1; if (!_isPlayingAudioPlayer1) { if (!_audioPlayer1.isPlaying) [_audioPlayer1 play]; else _audioPlayer1.currentTime = 0.0f; _isPlayingAudioPlayer1 = YES; } else { if (!_audioPlayer2.isPlaying)[_audioPlayer2 play]; else _audioPlayer2.currentTime = 0.0f; _isPlayingAudioPlayer1 = NO; } [self vibrate]; } - (void)pause { [_audioPlayer1 pause]; [_audioPlayer2 pause]; } - (void)stop { [_audioPlayer1 stop]; [_audioPlayer2 stop]; } - (void)vibrate { AudioServicesPlayAlertSound(kSystemSoundID_Vibrate); } @end
我们通过两个播放器。这里时候,如果我们使用了playOnce 方法,那么我们就判断当前是哪个播放器在播放,如果是播放器1,那么我们就用播放器2来播放。另一方面,如果两个播放器同时都在播放,我们就将播放时间拉到头,这样就和重新播放一样。通过这样的方式,我们在播放音效时就会感觉是多个音频。当然,如果要仿得更好的话,就是多弄几个AVAudioPlayer,不过这样会消耗更多的资源。
好了,就说到这吧!如果有不清楚或者发现程序有bug的可以发评论哈!
[本文为原创文章,如需转发,请注明出处:来自songrotek的博客!谢谢合作]