Building Loops the Smart Way in SpriteKit

The arrival of SpriteKit in iOS 7 changed the game for mobile developers. Quite literally in most cases. Fast and easy rendering with texture atlases meant that more animations could be bundled and displayed at one time, and the SKAction class gave developers a powerful way to schedule elaborate events in their game.

In typical Apple fashion though, not everything you need to make great interactive animations is available for you right out of the box. This series of blog posts will pick up where Apple left off, because trust me: they left off a lot.

First thing to keep in mind is that Apple does not allow SKActions to be subclassed, so any special behavior that you implement over and over has to be a method of some other class. Likely in a SKSpriteNode or SKNode subclass. This only becomes a huge bother when you want to reuse code across multiple games, and this restriction is largely unexplained.

So let’s begin with animation loops. A cornerstone of any game. Let’s say we have a texture atlas for our main character sprite that contains a walk loop and an idle loop. Let’s be smart and consistently name our files with five digit padding. (idleLoop_00000.png, idleLoop_00001.png, etc.)

To further condense the code, I've created, buildLoopFromAtlas:withFileNameFormat:, which is just one of many helper functions that we'll use. View below or see the gist on GitHub.

A lot of things are happening in this function, after we load the atlas up and declare the array that will hold our textures, we convert the fileFormat string from its original NSString format to Regex. This way, NSPredicate can filter the texture names to find all matching textures of the given animation sequence. Once we find all the frames that match, we loop through and add the textures to our texture array. We build an animation action from that array, nest that action in a repeatActionForever action, and return it.

The main reason we have to jump through all these hoops when building our loop is because of SKTextureAtlas returning the names of its stored textures in an arbitrary order. And just like SKAction, SKTextureAtlas can’t be subclassed either, so doing something like adding our own getOrderedTextureNames or getTextureNamesWithFormat functions to SKTextureAtlas is impossible.

So now we have two SKActions, one for our walk loop and another for our idle loop. Both run at 24 fps (the pre-decided animation speed) and can be stored in properties to be called later. How do we call these actions? How do we link them to other great things? Find out next week!