Sprite Kit Tutorial: Animations and Texture Atlases

Tony Dahbura
Smoky says: Only you can start this bear!

Smoky says: Only you can start this bear!

Note from Ray: Tutorial Team member Tony Dahbura has ported this tutorial from Cocos2D to Sprite Kit as part of the iOS 7 feast. We hope you enjoy!

In this Sprite Kit tutorial, you will learn how to create a simple animation of a bear walking using the brand new Sprite Kit framework that is part of iOS 7.

You’ll also learn how to make the animation efficient by using a texture atlas, how to make your bear move in response to touch events, and how to change the direction the bear faces based on where the bear is moving.

This tutorial assumes you at least know the basics of Sprite Kit. If you are completely new to Sprite Kit, be sure to check out our Sprite Kit Tutorial for Beginners first.

Let’s get started!

Create the Project

Let’s start by creating a Xcode skeleton for our project – create a new project File\New Project…, select the Sprite Kit Game framework in iOS Application and name it AnimatedBear:

Selecting the Sprite Kit Game template

Select Next and give the project the name AnimatedBear, Clear/Erase the Class Prefix field, and make sure the device is set for iPad.

Name Project and Choose iPad

Select Next and save the project to your disk.

Go ahead and run the project and you should see a Spaceship on your screen after you tap on the blue Hello World screen.

First Run with Template Code

Now that your project is ready, it’s time to get some art for your bear. You are going to use some already designed animation art courtesy of Vicki Wenderlich. Download the art from BearImages Art.

Examples of the bear images you will be using.

Examples of the bear images you will be using.

These images are saved in the maximum required resolution – for an iPad with a retina display (2X) as well as non-retina versions (1x). These files are named bear1..n@2x~ipad.png and bear1..n~ipad.png respectively.

You could just add these directly to your Sprite Kit project at this point and create an animation based on these individual images. However, there’s another way to create animations that is more efficient – by using a texture atlas.

Texture Atlas’ and Bears, Oh My!

If you haven’t used a texture atlas yet, think of them as gigantic images that you put your individual animation images within. They come with a file that specifies the boundaries for each individual sprite so you can pull them out when you need them within the code.

The reason why these are such a good idea to use is because Sprite Kit and the graphics engine is optimized for them. If you use sprites within a texture atlas properly, rather than making one OpenGL ES draw call per sprite it just makes one per texture atlas sheet.

In short – it’s faster, especially when you have a lot of sprites!

Xcode will automatically generate a file that specifies the boundaries for each individual sprite so you can pull them out when you need them within the code as well as creating the single image file with the images packed into it. This is all handled automatically for you at build time.

Note: When working with a texture atlas and things seem to not be current (wrong images etc) then you should do a clean on your project to force the texture atlas to recompile by selecting Product\Clean in Xcode.

Creating a folder for a texture atlas is as simple as placing your image files in a folder and appending .atlas on the end. Xcode will notice the .atlas extension and automatically combine the images into a texture atlas for you!

The artwork you just downloaded has a folder called BearImages.atlas created with the different resolutions ready to go. This folder just contains copies of all the graphics art from the other two folders.

Load the bear art into your application by dragging the folder called BearImages.atlas onto the AnimatedBear icon in your Xcode view:

Drag BearImages Atlas Folder into Xcode

After releasing from the drag, a dialog will appear giving the options on how to add this to your project, ensure that Copy items into destination group’s folder, Create groups for any added folder, and the AnimatedBear options are checked, and click Finish:

Select Proper Options After Drag

If you expand the folder in Xcode it should look like this:

Assets Folder View in Xcode

Now let’s get that bear moving!

A Simple Animation

You’re going to start just by plopping the bear in the middle of the screen and looping the animation so he moves forever, just to make sure things are working.

Start by cleaning up some of the pre-built code that the Sprite Kit template inserted.

Because you are using modern Objective-C capabilities the rest of your work will be in MyScene.m. Switch over to MyScene.m and replace the contents with the following:

#import <AVFoundation/AVFoundation.h>
#import "MyScene.h"

@implementation MyScene 
{
    
    SKSpriteNode *_bear;
    NSArray *_bearWalkingFrames;

}

-(id)initWithSize:(CGSize)size 
{
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        self.backgroundColor = [SKColor blackColor];
        
        // TODO...
       
    }
    return self;
}

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
}

@end

At this point you’ve just emptied out the project template to create a nice blank slate (and defined a few variables you’ll need later). Build and run to make sure everything builds OK – you should see a blank black screen.

There are 5 steps you will need to take to get this animation to work, so let’s cover them one at a time. Add each of these snippets to your initWithSize method in the “TODO” area shown by the comment.

1) Setup the array to hold the walking frames

NSMutableArray *walkFrames = [NSMutableArray array];

2) Load and setup the texture atlas

SKTextureAtlas *bearAnimatedAtlas = [SKTextureAtlas atlasNamed:@"BearImages"];

Create the atlas from the data in the application bundle. Sprite Kit will automatically look for the correct file based on the resolution of the device, on an iPad with a Retina display BearImages@2x~ipad.png will be used.

3) Gather the list of frames

int numImages = bearAnimatedAtlas.textureNames.count;
for (int i=1; i <= numImages/2; i++) {
    NSString *textureName = [NSString stringWithFormat:@"bear%d", i];
    SKTexture *temp = [bearAnimatedAtlas textureNamed:textureName];
    [walkFrames addObject:temp];
}
_bearWalkingFrames = walkFrames;

Create the list of frames by looping through your image's names (they are named with a convention of bear1.png -> bear8.png) and try to find a sprite frame by that name in the texture atlas. Notice the numImages variable being divided by 2...Why?

Solution Inside: Tell Me! SelectShow

4) Create the sprite, set its position to the middle of the screen, and add it to the scene

SKTexture *temp = _bearWalkingFrames[0];
_bear = [SKSpriteNode spriteNodeWithTexture:temp];
_bear.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:_bear];
[self walkingBear];

Create a sprite for your bear passing in a frame to start with, and center it in the middle of the screen. Call a the method to start the bear walking.

5) Add a new walking method below the initWithSize method

-(void)walkingBear
{
    //This is our general runAction method to make our bear walk.
    [_bear runAction:[SKAction repeatActionForever:
                      [SKAction animateWithTextures:_bearWalkingFrames
                                       timePerFrame:0.1f
                                             resize:NO
                                            restore:YES]] withKey:@"walkingInPlaceBear"];
    return;
}

This action will cause the animation to begin with a 0.1 second delay between frames. The "walkingInPlaceBear" key forces the animation to be removed if your code should call this method again to restart the animation. This will be important later on when to make sure animations are not stepping on each other. The withKey argument also provides a way to check on the animation to see if it is running by name.

The repeat action repeats whatever action it is provided forever, which results in the inner action animateWithTextures animating through the textures in our texture atlas in the order within the array.

Done!

And that's it! So build and run the project, and if all goes well you should see your bear happily strolling on the screen!

bearwalking

Changing Animation Facing Direction Based on Movement

Things are looking good - except you don't want this bear meandering about on its own, that would be dangerous! Would be much better if you could control its direction by touching the screen to tell it which way to go. Following that, we will look at moving him all over the screen.

Make the following changes to MyScene.m:

// Add these new methods
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{
    
    CGPoint location = [[touches anyObject] locationInNode:self];
    CGFloat multiplierForDirection;
 
    if (location.x <= CGRectGetMidX(self.frame)) {
        //walk left
        multiplierForDirection = 1;
    } else {
        //walk right
        multiplierForDirection = -1;
    }
    
    _bear.xScale = fabs(_bear.xScale) * multiplierForDirection;
    [self walkingBear];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{    
}

When you tap the screen and let go the touchesEnded method determines which side of the screen was tapped from the center. It uses this to determine which way the bear should face. Changing the direction of the bear sprite is accomplished in Sprite Kit by multiplying the xScale by its negative value to point left.

Build and run the project, and if all goes well you should see your bear happily strolling on the screen while changing direction when you tap the other side of the screen!

leftrightmoves

Moving the Bear Around the Screen

Let's get the bear so you can have him meander to different places on the screen.

Make the following changes to MyScene.m

// Comment out the call to start the bear walking
//[self walkingBear];

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{
    //Stuff from below!
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{    
}

//add this method
-(void)bearMoveEnded
{
    [_bear removeAllActions];
}

Starting at the beginning you are removing the existing code in the touchesEnded method. The meat of our code will go in here and it is a lot of stuff so we will break it into steps like before.

The bearMoveEnded method is called when you want to stop the animations. Our bear would look silly after reaching his new location if he kept walking!

Let's build out the touchesEnded method:

1) Determine the touch location and setup a variable for direction to face (as before)

CGPoint location = [[touches anyObject] locationInNode:self];
CGFloat multiplierForDirection;

Nothing new here - you just start by converting the touch point into local node coordinates using the usual method.

2) Set the desired velocity

CGSize screenSize = self.frame.size;
float bearVelocity = screenSize.width / 3.0;

Here you set up a velocity for the bear to move. You will estimate that it should take about 3 seconds for the bear to move the width of the screen. Since screen sizes can change from device to device you need to account for the width by asking the screen for its width, so since velocity is distance over time it would be the width pixels / 3 seconds.

3) Figure out the amount moved in X and Y

 CGPoint moveDifference = CGPointMake(location.x - _bear.position.x, location.y - _bear.position.y);

You need to figure out how far the bear is moving along both the x and y axis, by simply subtracting the bear's position from the touch location.

4) Figure out the actual length moved

float distanceToMove = sqrtf(moveDifference.x * moveDifference.x + moveDifference.y * moveDifference.y);

Now calculate the distance the bear actually moves along a straight line (the hypotenuse of a triangle formed from the bear's current position and the tap point). For a full tutorial on the math of game programming check out Trigonometry for Game Programming.

5) Figure out how long it will take to move

float moveDuration = distanceToMove / bearVelocity;

Calculate how long it should take the bear to move along this length, by simply dividing the length moved by the desired velocity.

6) Flip the animation if necessary

if (moveDifference.x < 0) {
    multiplierForDirection = 1;
} else {
    multiplierForDirection = -1;
}
_bear.xScale = fabs(_bear.xScale) * multiplierForDirection;

Next, you look to see if the bear is moving to the right or to the left by looking at the move difference. If it's less than 0, you're moving to the left and you can play the animation as-is. However, if it's moving to the right you need to flip your animation to the other way!

First instinct might be to run to your image editor and create new images for the bear facing the other direction, and use those. However, as you learned earlier this is accomplished by changing the xScale of the sprite through multiplication.

7) Run the appropriate actions

if ([_bear actionForKey:@"bearMoving"]) {
    //stop just the moving to a new location, but leave the walking legs movement running
    [_bear removeActionForKey:@"bearMoving"];
} //1
    
if (![_bear actionForKey:@"walkingInPlaceBear"]) {
    //if legs are not moving go ahead and start them
    [self walkingBear];  //start the bear walking
} //2
    
SKAction *moveAction = [SKAction moveTo:location duration:moveDuration];  //3
SKAction *doneAction = [SKAction runBlock:(dispatch_block_t)^() {
        NSLog(@"Animation Completed");
        [self bearMoveEnded];
}]; //4
    
SKAction *moveActionWithDone = [SKAction sequence:@[moveAction,doneAction]]; //5
        
[_bear runAction:moveActionWithDone withKey:@"bearMoving"]; //6
  1. Stop any existing move action (because you're about to override any existing command to tell the bear to go somewhere else!). The use of the key value allows you start and stop any named portion of the animations running.
  2. Start the legs moving on your bear if he is not already moving his legs, otherwise how can he walk to his new location. This makes use of the earlier method we had, which ensures we do not start an animation running that was already running through the use of the key name.
  3. You create a move action specifying where to move and how long it should take.
  4. You create a done action that utilizes a block to call a method to stop the animation upon reaching the destination.
  5. Set the two actions up as a sequence of actions, which means they will run in order sequentially (the first runs to completion, then the second runs). The sprite is assigned the action and told to run it with a key of "bearMoving". Remember, this key is used to see if your bear is en route to a new location (in step 1) should the user click a new location while one is in progress.

Note: Sprite Kit supports sequential and grouped actions. A sequential action means each specified action runs one after the other (sequentially). Some times you may want multiple actions to run at the same time. This is accomplished by specifying a grouped action where all the actions specified run in parallel.

You also have the flexibility to setup a series of sequential actions that contain grouped actions and vice versa! For more details see the Sprite Kit Programming Guide Chapter on Adding Actions to Nodes.

When the animation completes the bearMoveEnded is called and all animations are stopped as your bear awaits further directions.

Done!

A lot of code - but was it worth it? Build and run to see! If all works well you should be able to tap the screen to move your bear all around.

updated bear animation withmovement

Where To Go From Here?

Here is a sample project with all of the code you've developed in the above Sprite Kit tutorial.

Here are a few ideas to try out for some more animation fun:

  • What if you wanted the bear to moon walk? Hint:Try building the array of images backwards!
  • Try accelerating or slowing down the frame counts in the walkingBear method to see the effect.
  • Try animating multiple bears on the screen at the same time. Hint:Create multiple sprite nodes with actions.

At this point, you should know how to use animations in your projects. You should have some fun and experiment by creating your own animations and seeing what you can do!

If you want to learn more about Sprite Kit, you should check out our book iOS Games by Tutorials. We'll teach you everything you need to know - from physics, to tile maps, to particle systems, and even making your own 2D game art.

In the meantime, if you have any questions or comments, please join the forum discussion below!

Tony Dahbura

Tony is a hardware/software engineer from Virginia with more than 30 years software development experience. His first “real” computer was an Apple ][ and he has loved Apple Systems ever since! Tony has been working with iOS for about 3 years. He has worked on server systems, Java development, and various flavors of Unix.

In his spare time, after attending his kids sporting events, he does some independent software development work under FullMoon Manor LLC, helping folks realize the joy of custom apps to meet their needs. You can follow him on Twitter or connect on LinkedIn.

Other Items of Interest

Save time.
Learn more with our video courses.

raywenderlich.com Weekly

Sign up to receive the latest tutorials from raywenderlich.com each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 20 total!

Swift Team

... 15 total!

iOS Team

... 43 total!

Android Team

... 14 total!

macOS Team

... 11 total!

Unity Team

... 11 total!

Articles Team

... 12 total!

Resident Authors Team

... 16 total!