Update note: Tutorial Team member Tony Dahbura has ported this tutorial from Objective-C to Swift. We hope you enjoy!
In this Swift Sprite Kit tutorial, you will learn how to create a simple animation of a bear walking using the new Swift language and Sprite Kit framework.
You’ll also learn how to make the animation efficient by using texture atlases, 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 Swift Tutorial for Beginners first.
Let’s get started!
Create the Swift Project
Let’s start by creating a Xcode skeleton for our project. Start up Xcode, select File\New\Project…, choose the iOS\Application\Game template and click Next.
Enter AnimatedBearSwift for the Product Name, Swift for Language SpriteKit for Game Technology, iPad for Devices, and click Next:
Choose somewhere on your drive to save the project, and click Create.
Now that your project is open, select one of the iPad simulators and build and run to check out the starter project. After a brief splash screen, you should see the following:
If you tap on the screen you will see spaceships that start spinning. Spaceships! I thought we were doing a bear? Let’s fix that next, first let’s get some art for this project.
You are going to use some already designed animation art courtesy of GameArtGuppy. Download the art from BearImages Art.
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 like bear1@2x~ipad.png and bear1~ipad.png.
You could just add these directly to your Swift 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 bear sprite it just makes one per texture atlas sheet containing every bear image.
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 AnimatedBearSwift icon in your Xcode view:
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:
If you expand the folder in Xcode it should look like this:
Lastly, the template provided to you by Xcode has two issues. First, it’s set up the game to be Portrait, but you want landscape. Second, it is currently using Sprite Kit’s scene editor, which you don’t need for this tutorial. Let’s fix these issues.
First, open your target setting by clicking your AnimatedBearSwift project in the Project Navigator, then selecting the AnimatedBearSwift target. In the Deployment Info section, uncheck Portrait and Upside Down so only Landscape Left and Landscape Right are checked, as shown below:
Second, delete GameScene.sks from the project and choose Move to Trash when prompted. This file allows you to lay out sprites and other components of a scene visually, however for our bear game it’s easier to animate him programmatically, so you don’t need it.
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.
Open GameViewController.swift and replace the contents with the following:
import UIKit import SpriteKit class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let scene = GameScene(size: view.bounds.size) let skView = view as SKView skView.showsFPS = true skView.showsNodeCount = true skView.ignoresSiblingOrder = true scene.scaleMode = .ResizeFill skView.presentScene(scene) } override func prefersStatusBarHidden() -> Bool { return true } } |
You won’t need the starter code generated by Xcode so this implementation has just what you need to start.
GameViewController
is a normal UIViewController
, except that its root view is a SKView
, which is a view that contains a Sprite Kit scene.
Here, you’ve implemented viewDidLoad()
to create a new instance of the GameScene
on startup, with the same size of the view itself. Because you are using Sprite Kit the rest of your code will be in GameScene
.
You’re also overriding prefersStatusBarHidden()
to hide the status bar to focus all the attention on the bear.
Switch over to GameScene.swift
and replace the contents with the following:
import SpriteKit var bear : SKSpriteNode! var bearWalkingFrames : [SKTexture]! class GameScene: SKScene { override func didMoveToView(view: SKView) { /* Setup your scene here */ backgroundColor = (UIColor.blackColor()) } override func update(currentTime: CFTimeInterval) { /* Called before each frame is rendered */ } } |
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.
Setting up the Texture Atlas
First, you’ll need to load the texture atlas and set up the frames to animate them. Add the following code to the end of didMoveToView
:
let bearAnimatedAtlas = SKTextureAtlas(named: "BearImages") var walkFrames = [SKTexture]() let numImages = bearAnimatedAtlas.textureNames.count for var i=1; i<=numImages/2; i++ { let bearTextureName = "bear\(i)" walkFrames.append(bearAnimatedAtlas.textureNamed(bearTextureName)) } bearWalkingFrames = walkFrames |
First, you’re loading 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. walkFrames
is an array of SKTexture
objects and will store each frame of the bear animation.
Then you 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 do you only need to loop through half of the images in the texture atlas?
Next, add the following code directly after what you just added to the end of didMoveToView
:
let firstFrame = bearWalkingFrames[0] bear = SKSpriteNode(texture: firstFrame) bear.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame)) addChild(bear) |
Here, you’re grabbing the first frame and positioning it in the center of the screen to set up the start of the animation.
Next, add the following method to the class:
func walkingBear() { //This is our general runAction method to make our bear walk. bear.runAction(SKAction.repeatActionForever( SKAction.animateWithTextures(bearWalkingFrames, timePerFrame: 0.1, resize: false, restore: true)), withKey:"walkingInPlaceBear") } |
This action will cause the animation to begin with a 0.1 second delay between frames. The walkingInPlaceBear
key identifies this particular action with a name in case you call this method again to restart the animation. This will be important later on 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.
The repeat action repeats whatever action it is provided forever, which results in the inner action animateWithTextures
animating through the textures in the texture atlas in the order within the array.
Now all you need to do is call this method to kick off the animation! Add the following line to the end of didMoveToView
:
walkingBear() |
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!
Changing Animation Facing Direction
Things are looking good – except you don’t want this bear meandering about on its own; that would be dangerous! It would be much better if you could control its direction by touching the screen to tell it which way to go. Following that, you’ll look at moving him all over the screen.
Still in GameScene.swift, add the following methods to the class:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { /* Called when a touch begins */ } override func touchesEnded(touches: NSSet, withEvent event: UIEvent) { // Choose one of the touches to work with let touch = touches.anyObject() as UITouch let location = touch.locationInNode(self) var multiplierForDirection : CGFloat if (location.x <= CGRectGetMidX(self.frame)) { // walk left multiplierForDirection = 1.0 } else { // walk right multiplierForDirection = -1.0 } bear.xScale = fabs(bear.xScale) * multiplierForDirection walkingBear() } |
You’re only interested in when the user taps the screen, so you can leave touchesBegan
empty – this is called when the user puts their finger down.
When they bring their finger off the screen and complete the tap action, that’s when touchesEnded
is called. Here, the method determines which side of the screen was tapped – left or right of center. It uses this to determine which way the bear should face. The bear walks to the left by default, and you can change the direction of the bear sprite in Sprite Kit by multiplying the xScale
by -1.0 to flip the image so the bear faces to the right.
Likewise, you just multiply the scale to 1.0 to go back to the default left-facing bear.
Build and run the project, and if all goes well you should see your bear happily strolling on the screen as usual. Tap on the left and right sides of the screen to get the bear to change directions.
Moving the Bear Around the Screen
Right now, it looks like the bear is walking in-place on a treadmill. The next step is to get him to meander to different places on the screen.
First, remove the call to walkingBear()
at the end of didMoveToView
. You want the bear to start moving when the user taps the screen, not automatically.
Next, add this helper method to the class:
func bearMoveEnded() { bear.removeAllActions() } |
This will remove all actions and stop the animation. You’ll call this later when the bear reaches the edge of the screen.
The changes to get the bear to move to where the user touches will all be in touchesEnded
. Replace that method with the starter implementation below:
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) { // 1 let touch = touches.anyObject() as UITouch let location = touch.locationInNode(self) var multiplierForDirection: CGFloat // 2 let bearVelocity = self.frame.size.width / 3.0 // 3 let moveDifference = CGPointMake(location.x - bear.position.x, location.y - bear.position.y) let distanceToMove = sqrt(moveDifference.x * moveDifference.x + moveDifference.y * moveDifference.y) // 4 let moveDuration = distanceToMove / bearVelocity // 5 if (moveDifference.x < 0) { multiplierForDirection = 1.0 } else { multiplierForDirection = -1.0 } bear.xScale = fabs(bear.xScale) * multiplierForDirection } |
Here’s what’s going on step by step:
- Nothing new here – you just start by converting the touch point into local node coordinates using the usual method. You also declare a variable to hold the
multiplierDirection
as before to make the bear face in a different direction. - 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.
- You need to figure out how far the bear needs to move along both the x and y axes, by simply subtracting the bear’s position from the touch location. Then you can calculate the distance the bear 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.
- Calculate how long it should take the bear to move along this length, by simply dividing the length moved by the desired velocity.
- Finally, 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, he’s moving to the left; otherwise, to the right. You use the same technique of setting a multiplier for the
xScale
to flip the sprite.
Now all that’s left is to run the appropriate actions. That’s another substantial chunk of code; add the following to the end of touchesEnded
:
// 1 if (bear.actionForKey("bearMoving") != nil) { //stop just the moving to a new location, but leave the walking legs movement running bear.removeActionForKey("bearMoving") } // 2 if (bear.actionForKey("walkingInPlaceBear") == nil) { //if legs are not moving go ahead and start them walkingBear() } // 3 let moveAction = (SKAction.moveTo(location, duration:(Double(moveDuration)))) // 4 let doneAction = (SKAction.runBlock({ println("Animation Completed") self.bearMoveEnded() })) // 5 let moveActionWithDone = (SKAction.sequence([moveAction, doneAction])) bear.runAction(moveActionWithDone, withKey:"bearMoving") |
Here’s what’s happening in this second half of touchesEnded
:
- Stop any existing move action because you’re about to override any existing command to tell the bear to go somewhere else. Using the key value allows you start and stop any named portion of the animations running.
- Start the legs moving on your bear if he is not already moving his legs. This makes use of the earlier method which ensures you don’t start an animation running that was already running through the use of the key name.
- Create a move action specifying where to move and how long it should take.
- Create a done action that uses a block to call a method to stop the animation upon reaching the destination.
- Set up the two actions as a sequence of actions, which means they will run in order sequentially – the first runs to completion, then the second runs. Then you assign the action to the sprite and run it with the key “bearMoving”. Remember, you’re checking for this key at the top of the method to see if your bear is already en route to a new location in case the user taps a new location.
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.
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 around.
Where To Go From Here?
Here is the final 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 moonwalk? Hint: Try building the array of images backwards!
- Try accelerating or slowing down the frame counts in
walkingBear
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’ve seen how to make loading frames efficient with sprites and texture atlases – 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 and Swift, 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!
Sprite Kit Animations and Texture Atlases in Swift is a post from: Ray Wenderlich
The post Sprite Kit Animations and Texture Atlases in Swift appeared first on Ray Wenderlich.