在以前的博文中,我们已经讲解了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
我们在这里弄了两个AVAudioPlayer的实例,目的就是模拟 能在一个时间段内播放同一音频多次。
下面是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
这里主要是说一下功能实现的trick:
我们通过两个播放器。这里时候,如果我们使用了playOnce 方法,那么我们就判断当前是哪个播放器在播放,如果是播放器1,那么我们就用播放器2来播放。另一方面,如果两个播放器同时都在播放,我们就将播放时间拉到头,这样就和重新播放一样。通过这样的方式,我们在播放音效时就会感觉是多个音频。当然,如果要仿得更好的话,就是多弄几个AVAudioPlayer,不过这样会消耗更多的资源。
好了,就说到这吧!如果有不清楚或者发现程序有bug的可以发评论哈!
[本文为原创文章,如需转发,请注明出处:来自songrotek的博客!谢谢合作]