在以前的博文中,我們已經講解了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的部落格!謝謝合作]