3

我正在使用 Sprite Kit 为 iOS 9+ 开发游戏,最好使用 Swift 库。

目前我正在使用一个单例,我在其中预加载我的音频文件,每个文件都连接到一个单独的 AVAudioPlayer 实例。

这是一个简短的代码片段来了解这个想法:

import SpriteKit
import AudioToolbox
import AVFoundation

class AudioEngine {

    static let sharedInstance = AudioEngine()

    internal var sfxPing: AVAudioPlayer

    private init() {

        self.sfxPing = AVAudioPlayer()

        if let path = NSBundle.mainBundle().pathForResource("ping", ofType: "m4a") {
            do {
                let url = NSURL(fileURLWithPath:path)
                sfxPing = try AVAudioPlayer(contentsOfURL: url)
                sfxPing.prepareToPlay()
            } catch {
                print("ERROR: Can't load ping.m4a audio file.")
            }
        }

    }

}

这个 Singleton 在应用程序启动期间被初始化。在游戏循环中,我只需调用以下行来播放特定的音频文件:

AudioEngine.sharedInstance.sfxPing.play()

这基本上是可行的,但是当播放文件并且我的 iPad Air 上的帧速率从 60.0 下降到 56.0 时,我总是会出现故障。

有人知道如何用 AVAudioPlayer 解决这个性能问题吗?

我还留意了 3rd 方库,即:

要求:

  • 播放很多非常短的样本(如击球、击球等)
  • 播放一些运动效果(因此投球会很好)
  • 循环播放一些背景/环境声音
  • 没有讨厌的故障/帧率下降!

您能否根据我的要求推荐上述任何库或使用上述代码指出问题?

更新:

播放短音:

self.runAction(SKAction.playSoundFileNamed("sfx.caf", waitForCompletion: false))

确实提高了帧率。我将带有 Audiacity 的音频文件导出为 .caf 格式(Apple 的核心音频格式)。但是在本教程中,它们使用“ Signed 32-bit PCM”编码导出,这在我的情况下会导致音频播放受到干扰。使用任何其他编码选项(32-bit float、、、U-LawA-Law)对我来说都很好。

为什么使用caf格式?因为它是未压缩的,因此与压缩格式(如m4a. 对于在很短的间隔内播放很多短音效,这是有道理的,并且对于消耗几千字节的短音频文件,磁盘使用不会受到太大影响。对于较大的音频文件,例如环境音乐和背景音乐,使用压缩格式 ( mp3, m4a) 显然是更好的选择。

4

1 回答 1

3

根据您的问题,如果您为 iOS 9+ 开发游戏,您可以使用新的 iOS 9 库SKAudioNodeApple 官方文档):

var backgroundMusic: SKAudioNode!

例如,您可以将其添加到didMoveToView()

if let musicURL = NSBundle.mainBundle().URLForResource("music", withExtension: "m4a") {
    backgroundMusic = SKAudioNode(URL: musicURL)
    addChild(backgroundMusic)
}

你也可以用它来播放一个简单的效果:

let beep = SKAudioNode(fileNamed: "beep.wav")
beep.autoplayLooped = false
self.addChild(beep)

最后,如果你想改变音量:

beep.runAction(SKAction.changeVolumeTo(0.4, duration: 0))

更新

我看到您已经更新了关于AVAudioPlayerand的问题SKAction。我已经为我的 iOS8+ 兼容游戏测试了它们。

关于AVAudioPlayer,我个人使用我基于旧SKTAudio制作的自定义库。

我看到你的代码,关于 AVAudioPlayer init,我的代码是不同的,因为我使用:

@available(iOS 7.0, *)
    public init(contentsOfURL url: NSURL, fileTypeHint utiString: String?)

我不知道是否fileTypeHint会有所作为,所以请尝试向我介绍您的测试。

关于您的代码的优点:使用基于AVAudioPlayer您可以控制音量的共享实例音频管理器,随时随地使用您的管理器,确保与 iOS8 的兼容性

你的代码的缺点:每次你播放一个声音并且你想播放另一个声音时,以前的声音就会被破坏,特别是如果你启动了背景音乐。

怎么解决?根据this SO post,没有问题的工作似乎AVFoundation仅限于4个AVAudioPlayer属性实例化,所以你可以这样做:

  • 1)背景音乐播放器:AVAudioPlayer!
  • 2)soundEffectPlayer1:AVAudioPlayer!
  • 3)soundEffectPlayer2:AVAudioPlayer!
  • 4)soundEffectPlayer3:AVAudioPlayer!

您可以构建一个方法来切换 3 soundEffect 以查看是否被占用:

if player.playing

并使用下一个免费播放器。使用此解决方法,您始终可以正确播放声音,甚至是背景音乐。

于 2016-07-20T17:13:06.933 回答