Swift Spritekit Playing Audio in the Background

Swift SpriteKit playing audio in the background

SKAction is really easy to use with sounds, but sometimes you might want to do more.

In that case, you would want to use AVAudioPlayerinstead of it.

In order to not write your own "player", I suggest you to use an existing one. Here is one I've already used (SKTAudio) : https://github.com/raywenderlich/SKTUtils/blob/master/SKTUtils/SKTAudio.swift

Here is how to use it :

// For background audio (playing continuously)
SKTAudio.sharedInstance().playBackgroundMusic("yourBackgroundMusic.mp3") // Start the music
SKTAudio.sharedInstance().pauseBackgroundMusic() // Pause the music
SKTAudio.sharedInstance().resumeBackgroundMusic() // Resume the music

// For short sounds
SKTAudio.sharedInstance().playSoundEffect("sound.wav") // Play the sound once

As you can see, you'll be able to either play short sound (as you might already have done with SKAction) and even background music that will play in loop as you're looking for.

Swift Spritekit: background music not playing

I think the reason it won't play is because the audio node would be deallocated once the scene changes. I'm not sure why it's only playing in between transitions. I've also never used an audio node, but I did create my own custom class to handle all the audio.

Also, I would not copy and paste code. You have the same code in both scenes when you can just have a single class to handle audio. Here's a solution using a custom class I made called JKAudioPlayer. Just create a new Swift class and paste the code in it. Because the audio object declared later is not part of a scene, it will continue/allow music to play when you transition.

import Foundation
import SpriteKit
import AVFoundation
import AVFoundation.AVAudioSession

/**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.*/
public class JKAudioPlayer {

/**Used to access music.*/
var musicPlayer: 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. */
public 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).*/
public func playMusic(fileName: String, withExtension type: String = "") {
if let url = NSBundle.mainBundle().URLForResource(fileName, withExtension: type) {
musicPlayer = try? AVAudioPlayer(contentsOfURL: url)
musicPlayer.numberOfLoops = -1
musicPlayer.prepareToPlay()
musicPlayer.play()
}
}

/**Stops the music. Use the "resumeMusic" method to turn it back on. */
public func stopMusic() {
if musicPlayer != nil && musicPlayer!.playing {
musicPlayer.currentTime = 0
musicPlayer.stop()
}
}

/**Pauses the music. Use the "resumeMusic" method to turn it back on. */
public func pauseMusic() {
if musicPlayer != nil && musicPlayer!.playing {
musicPlayer.pause()
}
}

/**Resumes the music after being stopped or paused. */
public func resumeMusic() {
if musicPlayer != nil && !musicPlayer!.playing {
musicPlayer.play()
}
}

/**Plays a sound only once. Must be used inside a runAction(...) method.*/
public func playSound(fileName: String) -> SKAction? {
return SKAction.playSoundFileNamed(fileName, waitForCompletion: false)
}
}

To use it, create a global variable that has access to the audio.

let audio = JKAudioPlayer.sharedInstance()

Then when you want to play music, you can easily call this in the didMoveToView function of the scene class.

audio.playMusic("MusicName")

And you also have a way to control it simply by calling the pause/stop/resume music functions like this:

audio.stopMusic()

If you want the user to be able to play their own music in the background, for example from their iTunes library without your app pausing their music, then you can just set canShareAudio to true in the GameViewController's viewDidLoad function.

audio.canShareAudio = true

How do you add background music to SpriteKit?

(Xcode 8 and Swift 3)

Using SpriteKit this is pretty simple. You create an SKAudioNote with a sound file and then you attach it to your Scene as a child. It will loop by default:

override func didMove(to view: SKView) {
let backgroundSound = SKAudioNode(fileNamed: "bg.mp3")
self.addChild(backgroundSound)
}

If you want to stop the background music at some point you can use the build in methods:

    backgroundSound.run(SKAction.stop())

Or maybe you want to play the sound again after stopping it:

    backgroundSound.run(SKAction.play())

SpriteKit makes this really simple. I hope this helps you.

Stopping Audio In Spritekit Swift

If you're able to target iOS 9, there's a marvellous solution for this: SKAudioNode. It lets you play music and stop it whenever you want, plus it automatically loops when it's attached to a node.

To try it out, make a property like this:

var backgroundMusic: SKAudioNode!

Then add this to didMoveToView():

backgroundMusic = SKAudioNode(fileNamed: "music.m4a")
addChild(backgroundMusic)

That's all it takes to start playing! When you want it to stop, use this:

backgroundMusic.runAction(SKAction.stop())

Swift / Spritekit: Play music through specific scenes

What you might want to do is use a Singleton. Doing so, you'll be able to have a sound player available from anywhere within your app.

Here is one that might fit your needs : https://github.com/raywenderlich/SKTUtils/blob/master/SKTUtils/SKTAudio.swift (Ray Wenderlich).

Used like so : SKTAudio.sharedInstance().playBackgroundMusic(filename: yourTutorialMusicName). Then in your menu you call it again with your other music.

Let me know if it helped.

How stop SKAction background music

I've had the same issue a while ago: This is how I got it working. This is specific for background music.

   var backgroundMusic: AVAudioPlayer!

func playMusic() {
if let musicURL = Bundle.main.url(forResource: "musicSource", withExtension: "wav") {
if let audioPlayer = try? AVAudioPlayer(contentsOf: musicURL) {
backgroundMusic = audioPlayer
backgroundMusic.numberOfLoops = -1
backgroundMusic.play()
backgroundMusic.volume = 0.2

}
}
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)

if let touch = touches.first {
let pos = touch.location(in: self)
let node = self.atPoint(pos)

let musicOff = UserDefaults.standard.bool(forKey: "musicOff")

if node == musicButton && musicOff == false {

backgroundMusic.stop()
UserDefaults.standard.set(true, forKey: "musicOff")

}

if node == musicButton && musicOff == true {

backgroundMusic.play()
backgroundMusic.volume = 0.3
UserDefaults.standard.set(false, forKey: "musicOff")

}
}
}

SpriteKit doesn't play any music with either SKAudioNode or SKAction.playSoundFileNamed

In my case
Audio files are in Assets.xcassets.
but that's wrong.
Just put all audio files under project group.



Related Topics



Leave a reply



Submit