我对这个问题非常恼火,所以我创建了自己的自定义类 JKAudioPlayer 来暂时避免这个问题并为我处理所有音频。
它有 2 个 AVAudioPlayer 对象。 1 播放音乐,1 播放声音。
这是课程。
import Foundation
import SpriteKit
import AVFoundation
/**Manages a shared instance of JKAudioPlayer.*/
private let JKAudioInstance = JKAudioPlayer()
/**Provides an easy way to play sounds and music. Use sharedInstance method to access
a single object for the entire game to manage the sound and music.*/
open class JKAudioPlayer {
/**Used to access music.*/
var musicPlayer: AVAudioPlayer!
var soundPlayer: AVAudioPlayer!
/** Allows the audio to be shared with other music (such as music being played from your music app).
If this setting is false, music you play from your music player will stop when this app's music starts.
Default set by Apple is false. */
static var canShareAudio = false {
didSet {
canShareAudio ? try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
: try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
}
}
/**Creates an instance of the JAAudio class so the user doesn't have to make
their own instance and allows use of the functions. */
open class func sharedInstance() -> JKAudioPlayer {
return JKAudioInstance
}
/**Plays music. You can ignore the "type" property if you include the full name with extension
in the "filename" property. Set "canShareAudio" to true if you want other music to be able
to play at the same time (default by Apple is false).*/
open func playMusic(_ fileName: String, withExtension type: String = "") {
if let url = Bundle.main.url(forResource: fileName, withExtension: type) {
musicPlayer = try? AVAudioPlayer(contentsOf: url)
musicPlayer.numberOfLoops = -1
musicPlayer.prepareToPlay()
musicPlayer.play()
}
}
/**Stops the music. Use the "resumeMusic" method to turn it back on. */
open func stopMusic() {
if musicPlayer != nil && musicPlayer!.isPlaying {
musicPlayer.currentTime = 0
musicPlayer.stop()
}
}
/**Pauses the music. Use the "resumeMusic" method to turn it back on. */
open func pauseMusic() {
if musicPlayer != nil && musicPlayer!.isPlaying {
musicPlayer.pause()
}
}
/**Resumes the music after being stopped or paused. */
open func resumeMusic() {
if musicPlayer != nil && !musicPlayer!.isPlaying {
musicPlayer.play()
}
}
/**Plays a single sound.*/
open func playSoundEffect(named fileName: String) {
if let url = Bundle.main.url(forResource: fileName, withExtension: "") {
soundPlayer = try? AVAudioPlayer(contentsOf: url)
soundPlayer.stop()
soundPlayer.numberOfLoops = 1
soundPlayer.prepareToPlay()
soundPlayer.play()
}
}
}
这是我的使用方法。首先,创建一个全局变量来处理音频(或者如果需要,也可以只是声音)。
let audio = JKAudioPlayer.sharedInstance()
然后,只要您想播放声音,就这样做。
audio.playSoundEffect(named: "SoundFileName.type")
你的声音应该会播放。您必须在字符串中包含文件的类型。我完全摆脱了所有播放声音的 SKAction 并将它们更改为我的代码。现在一切都很完美,没有错误。我也将这个类与我的 JKButtonNode 一起使用来播放声音。
为了记录,我将所有声音文件从 .mp3 制作成 .wav。我不知道这是否是它起作用的原因,但我在遇到 SKAction 错误时将它们全部切换了。
另外,我为我添加了一个快捷方式。如果您希望用户能够在玩游戏的同时播放音乐,您可以在 GameViewController 中添加此代码。
JKAudioPlayer.canShareAudio = true