SpriteKit那些讓我神傷的坑(3):致命的音效

致命的音效

音效是游戲的一個(gè)重要元素。SpriteKit對音效也提供了支持。
在SpriteKit中有2種方式來播放音效:

  1. 使用SKAudioNode:
audioNode = SKAudioNode(fileNamed: filename)
        audioNode!.autoplayLooped = false
        self.addChild(audioNode!)
        audioNode!.runAction(SKAction.play())

2.使用SKAction.playSoundFileNamed:

let soundAction = SKAction.playSoundFileNamed("\(towerType.rawValue)Fire.mp3", waitForCompletion: false)

這是Apple官方推薦的方法,幾乎所有的SpriteKit教程也都是用的這2種方式。
如果你像我一樣,在游戲中有很多音效需要不斷播放的話,你會面臨兩個(gè)問題:
1.在多個(gè)音效一起播放的時(shí)候,你偶然會遇到一個(gè)uncaught exception

*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: _engine->IsRunning()'

2.反復(fù)播放后你會發(fā)現(xiàn)內(nèi)存只增不減。
這兩個(gè)問題都會造成應(yīng)用崩潰。第一種是偶然性的崩潰,第二種是累積性的崩潰。
所以我說,這是致命的音效

觀察到這個(gè)現(xiàn)象后,這個(gè)問題困擾我2個(gè)星期的時(shí)間。查了各種資料。
有人用延遲了解決第一個(gè)問題。
比如:
https://forums.developer.apple.com/thread/27980
但是效果并不完美。

解決方法

經(jīng)過探索我終于意識到,SpriteKit的音效播放本身存在問題。
只有徹底放棄它才可以使問題得到解決。
經(jīng)過驗(yàn)證,以下2種方式都可以成功:

方法一:AudioServicesPlaySystemSound

var dict = [String:SystemSoundID]()
    
    func play(fileName:String){
        
        if let soundId = dict[fileName] {
            AudioServicesPlaySystemSound(soundId)
        } else if let soundURL = NSBundle.mainBundle().URLForResource(fileName, withExtension: "mp3") {
            var mySound: SystemSoundID = 0
            AudioServicesCreateSystemSoundID(soundURL, &mySound)
            dict[fileName] = mySound
            AudioServicesPlaySystemSound(mySound)
        }
    }

方法二:AVAudioPlayer

var dict2 = [String:AVAudioPlayer]()
    
    func play(fileName:String){
        
        if let player = dict2[fileName] {
            player.play()
        } else{
            let path = NSBundle.mainBundle().pathForResource(fileName, ofType:"mp3")!
            let url = NSURL(fileURLWithPath: path)
            do {
                let sound = try AVAudioPlayer(contentsOfURL: url)
                //player = sound
                dict2[fileName] = sound
                sound.playAtTime(0)
            } catch {
                // couldn't load file :(
            }
        }
    }

注意,在我的游戲中,幾個(gè)聲音文件(.mp3)反復(fù)播放,所以我將它們放在Dictionary中,避免每次都要加載。
使用后,崩潰沒了,內(nèi)存的使用也終于正常了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容