Playing sounds in Sprite Kit using SKAction

This article discusses adding sound effects to a Sprite Kit project using SKAction and provides you with a couple of tips and tricks and useful code snippets. It also explains performance issues that may appear when dealing with sounds not in the best, most efficient way and gives insights into how to avoid these problems.

Using SKAction

There are many ways you can play sounds in Sprite Kit game. The easiest way of playing a sound file is using a SKAction. It has a built-in method for handling audio playback.

+ (SKAction *)playSoundFileNamed:(NSString*)soundFile
               waitForCompletion:(BOOL)wait;

The method simply creates an action that plays a sound. Sound file name must be the name or path of a file of a platform supported audio file format. Apple recommends using a LinearPCM format audio file with 8 or 16 bits per channel for best performance. After creating the action one has to run it to hear the effect.

[[self scene] runAction:[SKAction playSoundFileNamed:@"sound.caf"
      waitForCompletion:NO]];

iOS and macOS have a native audio file format, the Core Audio Format (or CAF) file format. CAF should be your first choice format. However, you can also use other formats like AIFF, WAV or even MP3. Full list of supported audio file formats on macOS and iOS can be found here (iOS) and here (OS X). Keep in mind that for very short sound files, say shorter than 4 seconds, MP3 isn’t ideal since MP3 file is buffered into a 250KB buffer. Try CAF or WAV instead.

When using SKAction‘s playSoundFileNamed: method one has to remember to cache the action if it’s executed many times. Not doing this might result in a nasty ‘Failed to Load Resource’ crash when the sound file is being loaded simultaneously by many SKAction instances.

Terminating app due to uncaught exception ‘Failed to Load Resource’, reason: ‘Resource sound.wav can not be loaded’

Moreover, for performance reasons, unnecessary disk operations should be avoided. So we should create a SKAction that represents playing the sound, and reuse that object so the audio file is only loaded once. Thus, the best way of doing this is to store the repeated action in a static variable. The following sample code shows a good example of how to do it.

static SKAction *sharedMissileLaunchSoundAction = nil;

- (SKAction *)missileSoundAction {
    return sharedMissileLaunchSoundAction;
}

+ (void)loadSharedAssets {
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        sharedMissileLaunchSoundAction = [SKAction playSoundFileNamed:@"missile.caf"
                                                    waitForCompletion:NO];
    });
}

Drawbacks of SKAction approach

Playing sounds using SKAction is very simple and straightforward. However there is no way you can configure the way the sound is played. The biggest drawback is that there is no way of controlling the volume of the sound played using the playSoundFileNamed:method. If you need more flexibility in playing the sounds you might consider using [AVAudioPlayer`](https://developer.apple.com/documentation/avfoundation/avaudioplayer).

However, for simple games that do not require sophisticated audio engines, using SKAction‘s to play sound is the best and the fastest way.

Related