A Platform game in F# and SpriteKit – Part 5 – Animation and Sound

Last time we added some scrolling to out game, but our main character looks rather static. Let’s let him move like Jagger (well maybe  Cliff Richard)

Animation!

SpriteKit is clever. It’s possible to give SpriteKit a bunch of textures and it will process them into a single large texture and allow you to look up into it to get the original image out by name. This is called an Atlas.

This is going to come in handy for animation as we can preload all our frames and then cycle through them. To achieve this, firstly we need to add a folder to Resources. The name of the folder is important here – if it ends in ‘.atlas’ then the files inside will be processed into a single SKTextureAtlas.

So in the project I’ve got Player.atlas filled with 11 frames of running animation:

Files

So now it builds lets look at loading the atlas:

let playerAtlas = SKTextureAtlas.FromName "Player"
let playerAnimationTextures = playerAtlas.TextureNames.[1..playerAtlas.TextureNames.Length-1]
    |>Array.sort
    |>Array.map playerAtlas.TextureNamed

Couple of interesting points
1: When you load the atlas it’s the name of the folder minus the .atlas.

2: Note the Array slicing on line 2 – the texture at position 0 is the complete texture  so we skip that using slicing – nice!

3: We sort the textures in the atlas by name – as the files are the same prefix, but numbered we get the right order – the array of TextureNames is unordered, so without the sort the animation would look – strange…

Once we’ve loaded in we’ll make our player SpriteNode use the atlas and animate it like this:

let animation = SKAction.AnimateWithTextures(playerAnimationTextures, 0.05) 
                |> SKAction.RepeatActionForever
player.RunAction animation

Again – a little gotcha – the 2nd parameter of AnimateWithTextures is not the total run time of the animation (as it is with the other SKActions we have come across so far) – it’s the time for EACH FRAME. So we run our animation at 20fps.

IMPORTANT NOTE:

I did the above and IT DIDNT WORK (first time). In the interest of sharing knowledge and saving you good readers time I found the command line util, documented it, ran it, found how to add the results to the project so it all worked. This took me around 3 hours.

After doing all that, I discovered that what I really need to do was to REBUILD the solution, and a little message popped up in the build messages saying “Generating Texture Atlases” – and it worked like magic.

So when in doubt – REBUILD!

Now our little fella looks a bit lively. But it sure is quiet in here:

Music

Now for adding music I’m going to step away from SpriteKit for now and use AVFoundation. SpriteKit does provide some support for sound effects, but for MP3s we have to look to other Apple APIs. Luckily due to Apple’s iPod heritage handling MP3 is fairly straightforward.

In an ideal world the code to load and play an MP3 would look something like this:

let mutable error : NSError = null
use audioplayer = new AVAudioPlayer(NSUrl.FromFilename song, "mp3", &error)
audioplayer.NumberOfLoops <- -1 //Loop forever
ignore <| audioplayer.Play()

But unfortunately when you run this code you get a fraction of a second of music then it stops. This seems to come up quite often on StackOverflow. The solutions there usually refer to workarounds for ARC in objective-C. Once again F# is going to make our lives easier than those native boys.

let playSong song = 
     let mutable error : NSError = null
     let audioplayer = new AVAudioPlayer(NSUrl.FromFilename song, "mp3", &error)
     ignore <| audioplayer.Retain() //Without this line the audio immediately stops
     audioplayer.NumberOfLoops <- -1 //Loop forever
     ignore <| audioplayer.Play()
     { new IDisposable with
           member __.Dispose() = 
               audioplayer.Stop()
               audioplayer.Release() 
               audioplayer.Dispose()}

The key parts here:
1: The Retain call ensures that the AVAudioPlayer is not automatically released.
2: We return an IDisposable which is an object expression to handle resource de-allocation.

So to consume this new method we simply:

use song = playSong "Level1.mp3"

Now when we finish up in the level async workflow, dispose is called and cleans up automatically.

Finishing off

Today we’ve got our dude looking a bit more lively and made his world a little a little nicer with some funky music (all once again thanks to open.commonly.cc). I personally struggled to get what should have been easy working, but hopefully my pain is your gain.

As always – complete source is here and the code from today is here.

Next time I’ll continue giving you aural pleasure by adding some sound effects.

Advertisements

About thedo666

Software developer trying to learn a new language - English!
This entry was posted in F#, iOS and tagged , , , . Bookmark the permalink.

One Response to A Platform game in F# and SpriteKit – Part 5 – Animation and Sound

  1. Pingback: F# Weekly #42, 2013 | Sergey Tihon's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s