Game development tutorial: Swift and SpriteKit – Part 3 Texture Atlases

 

In the previous tutorial part we looked at working with a single Sprite.  Reality is, very few games are composed of singular sprites.  UI’s are made up of a number of different sprites, animations are composed of several different frames, each composed of a single image.  Loading hundreds of individual textures is not good for performance.  A very common solution is to use a texture atlas ( or sprite sheet ).  Fortunately Xcode make it extremely easy.

 

We are going to use the same sprite we did in the previous tutorial, you can download it here.  As you can see, it’s actually a zip file containing a number of png images:

Ta1

 

Extract the zip file and rename it jet.atlas.

Now in Xcode, in Project Navigator, right click your project and select Add to Project

Ta2

 

Select the directory ( not the files ) and click add.  Defaults should be ok, but make sure it’s set to copy.

Ta3

 

And you are done.  The following code:

import SpriteKit

 

class GameScene: SKScene {

    

    override func didMoveToView(view: SKView) {

        var sprite = SKSpriteNode(imageNamed:“sprite4”)

        sprite.xScale = 4

        sprite.yScale = 4

        sprite.position = CGPoint(x:0,y:0)

        view.scene!.anchorPoint = CGPoint(x: 0.5,y: 0.5)

        self.addChild(sprite)

    }

    

}

 

Will load the sprite from the Atlas that had the file name “sprite4.png”.  NOTE HOWEVER, if you add an image named sprite4 to your project, it will be loaded instead of the Texture Atlas.

 

So, what exactly did Xcode do?  We behind the scenes, it went ahead an combined all of your images together into a single OpenGL optimized image, and created a reference file telling SpriteKit how to access it.  Let’s take a look at the results.

 

First, build your game.  Select Product->Build For->Running

Ta4

 

You should now have a Products folder in your project.  Right click the .app file for your project and select Show in Finder:

Ta5

 

Now right click the .app file and select Show Package Contents:

Ta6

 

Navigate into contents->resources->jet.atlasc and you will see two files, one is an image, the other a plist.  Let’s look at the image first:

 

Jet 1

 

That’s out images smash together in a power of 2 friendly texture that your GPU can handle efficiently.  The plist file:

Ta7

 

This plist shows SpriteKit how to access each individual image within the larger image.  To you however the process is pretty transparent.  Basically group all common images together in a directory.  Give the directory a .atlas name and add it to your project, then access each image as you would normally.

 

Sometimes however you may want to access the TextureAtlas itself.  You can do that as well, let’s take a look at how:

import SpriteKit

 

class GameScene: SKScene {

    let textureAtlas = SKTextureAtlas(named:“jet.atlas”)

    var currentTexture:Int = 1;

    

    override func didMoveToView(view: SKView) {

        view.scene!.anchorPoint = CGPoint(x: 0.5,y: 0.5)

        

        let sprite=SKSpriteNode(texture:textureAtlas.textureNamed(“sprite1”))

        sprite.xScale = 8

        sprite.yScale = 8

        self.addChild(sprite)

    }

    

    override func keyDown(theEvent: NSEvent!) {

        // On any key press move to the next texture

        var sprite = self.scene.children[0] asSKSpriteNode

 

        switch currentTexture {

            case 1:

                sprite.texture = textureAtlas.textureNamed(“sprite2”)

            case 2:

                sprite.texture = textureAtlas.textureNamed(“sprite3”)

            case 3:

                sprite.texture = textureAtlas.textureNamed(“sprite1”)

            default:

                break

        }

        ++currentTexture

        if(currentTexture > 3) {

            currentTexture = 1

        }

    }

}

 

Now run it, and each time you press a key it will advance to the next frame.

 

 

 

First let me stop right here and make one thing perfectly clear… THIS IS NOT HOW YOU DO ANIMATION! 🙂  We will cover animation later. This was just a small code segment to illustrate how to access a TextureAtlas directly.  

 

As you can see, it’s as simple a matter as creating an SKTextureAtlas and passing in the file name.  You can then access each individual SKTexture within the atlas using textureNamed passing in the file name you used for the original image in the atlas directory.  As you can see, you do not need to pass in the file extension.  Here we see a Swift switch statement in action.  Switch statements are important to Swift and quite capable.  You can switch on Ints like we have done here, but you can also use strings. It is tempting to use the sprite name here, but an important thing to realize is the SKSprite name is NOT the same as the SKTexture name.  Unless you manually name the sprite, it will be nil.  Unlike C++, case statements in Swift do not fall through, so you do not need to provide a break statement for each case.  However, there are two caveats to be aware of.  First, every single possible value must be handled.  If you don’t want to handle every possible value you can provide a default handler which will catch everything else.  However each case ( even default ) must contain at least one executable statement, thus the break in default.  This only scratches the surface of switch… you can also specify multiple values in a case using commas, provide ranges using the .. and … operators, etc.

 

That’s it for TextureAtlases, on to the next part!


Scroll to Top