Introduction
If you’re an aspiring game developer or just want to target the iOS or macOS realms, you must know your way around SpriteKit.
In case you didn’t know, SpriteKit is a game development framework provided by Apple, that offers a lot of tools and speeds up the development of your game, by allowing you to focus on actually creating your game.
In this tutorial, we will go through the basics of handling sprites and animations, but that’s enough talk, let’s create our new project and start learning.
BUILD GAMES
FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.
You can download the final source code here.
Sprite Basics
Let’s start by creating a new project, open Xcode and select File -> New -> Project, and fill the fields as follows:
- Product Name: SpriteBasics
- Organization Name: SwiftLudus
- Organization Identifier: org.swiftludus
- Language: Swift
- Game Technology: SpriteKit
- Devices: Universal
- And uncheck both test options, we won’t be using them
Alright, now that our project is created, let’s add a simple sprite, you can download the images we’re going to use in this tutorial here, and we will start by using the image named “Idle.png”.
To add the sprite to our project, we simply need to locate the Assets.xcassets folder, then drag the image file into it, and that’s all there is to it.
It’s better if we start from a clean slate, so let’s replace the contents GameScene.swift file with the following code:
import SpriteKit class GameScene: SKScene { override func didMoveToView(view: SKView) { /* Setup your scene here */ } }
Now we can show the image, to do so, we need to create a sprite, so place the following line inside the didMoveToView function:
let sprite = SKSpriteNode(imageNamed: "Left.png") self.addChild(sprite)
Let’s what this gets us, run the application.
Nothing.
What’s going on? Well, the thing is that the SpriteKit scene, by default is larger than the screen of the phone, so the sprite is actually in the scene but not in the screen
There a couple of ways that we can get around that, but to keep things simple and to the point, we’ll just position the sprite in the middle of the screen, which also happens to be the middle of the scene.
Place the following lines after the sprite creation:
let position = CGPoint(x: self.size.width / 2, y: self.size.height / 2) sprite.position = position
You should see something similar as the picture below:
Awesome! The sprite now appears in the middle of the screen, but it is a bit large, isn’t it? Let’s fix that.
There are a couple of ways to modify sprite dimensions, but we’re going to use the scaling approach, to accomplish that, we just need to add the following lines after we create the sprite:
sprite.xScale = 0.5 sprite.yScale = 0.5
You should now see the sprite with half its original dimensions.
Anchor Point & Rotation
When it comes to sprites and rotation, there is a very important concept that we need to grasp first, and it is the anchor point. So, what is it?
You can think of the anchor point, as the reference point used to position your sprite, for example, when we set the sprite’s position to the middle of the screen, what is actually positioned in the middle of the screen, is the sprite’s anchor point, by default it is positioned right in the middle of the sprite.
To change the anchor point’s location, and to see what it really does, we’re going to modify the sprite’s anchorPoint property, add the following after the sprite is created:
sprite.anchorPoint = CGPoint(x: 0, y: 0)
Run the game, and you should see that the sprite has moved a bit up and to the right.
Why is that? Well, to better see what’s going on, let’s add a circle to sprite, place the following lines of code in the end of the didMoveToView method:
let circle = SKShapeNode(circleOfRadius: 100) circle.xScale = 0.15 circle.yScale = 0.15 circle.fillColor = SKColor.blueColor() circle.zPosition = 1 sprite.addChild(circle)
Run the game, and depending on where you have the anchor point, you can now see a blue circle representing it.
Here’s an exercise for you, try out different coordinates for the sprite’s anchor point and see what that does.
For reference, check out the image below detailing the coordinate system for the anchor point:
Rotating the sprite is also convenient, we just have to do a small conversion from degrees to radians, this is because the property that we need to modify expects the value in radians, but it’s simpler to think in degrees.
Add the following line after we set the anchor point to the sprite:
sprite.zRotation = CGFloat(3*M_PI/2)
This will show the sprite facing down.
Play with the rotation and the angles/radians to better understand what’s going on.
For reference, take a look to the image below showing the different angles and radians that we can use:
Just keep in mind that the sprite isn’t initially rotated, that means it has a 0 degree rotation, so rotating it 90 degrees or PI / 2 radians will “move” it to the left, but rotating it 270 degrees or 3 * PI / 2 radians will “move” it to the right.
Texture Atlases
A texture atlas, or sprite sheet, is one large image file, containing several sub-images, which can then be rendered by just loading the fire image file and specifying the sub-image coordinates inside it’s father.
Atlas are used mostly for improving memory usage, but it’s also a convenient way to group related images, such as animations or tiles. There are tons of tools that can be used to create them, but thankfully Xcode provides a convenient way to create a texture atlas, which we’ll do next.
First of, let’s clean up our “GameScene” class, it is already cluttered with unnecessary code, so replace it’s contents with:
import SpriteKit class GameScene: SKScene { override func didMoveToView(view: SKView) { let sprite = SKSpriteNode(imageNamed: "Idle.png") self.addChild(sprite) let position = CGPoint(x: self.size.width / 2, y: self.size.height / 2) sprite.position = position sprite.xScale = 0.5 sprite.yScale = 0.5 } }
To create a texture atlas, all we need to do is create a folder with a “.atlas” at the end of the name, place the images we want to contained there, and then we just need to add that folder to our Xcode project, and that’s it. Simple huh?
Let’s create our atlas now:
- Create a folder inside the project directory (next to your Swift source files), named “RobotAnimations.atlas”.
- Take all of the “Melee” and “Jump” images and place them inside the newly created folder.
- Go to Xcode, choose File -> Add Files to “Project Name”, and select the “RobotAnimations.atlas” folder.
That’s it!
Now you are probably wondering how we can use them, and that is actually the great advantage that this way of creating texture atlases has, the usage does not change! Let’s see it in action.
All we need to do to verify that the images inside the atlas work, is to change the sprite name we are loading in our “GameScene”, replaced the following line:
let sprite = SKSpriteNode(imageNamed: "Idle.png")
With the first melee sprite:
let sprite = SKSpriteNode(imageNamed: "Melee1.png")
Run the application, you’ll see that the robot is now ready to attack!
It was really easy to group together our images, and also save some memory in the way. Cool!
Animations
Now that we have covered the basics, we get to do something fun, we’re going to create an animation using the other images you downloaded before, and we will also use the atlas created in the previous section, we will first create a melee attack animation for our robot.
To create an animation, we need an array of images that are going to be displayed in succession, so we will start with that to go step by step.
We will use another approach to load the sub-images from the atlas, by first loading the atlas, and then grabbing the images by their name, we can accomplish that by adding the following lines of code at the end of the “didMoveToView” method:
let atlas = SKTextureAtlas(named: "RobotAnimations") let m1 = atlas.textureNamed("Melee1.png") let m2 = atlas.textureNamed("Melee2.png") let m3 = atlas.textureNamed("Melee3.png") let m4 = atlas.textureNamed("Melee4.png") let m5 = atlas.textureNamed("Melee5.png") let m6 = atlas.textureNamed("Melee6.png") let m7 = atlas.textureNamed("Melee7.png") let m8 = atlas.textureNamed("Melee8.png")
The previous code does nothing yet, but this is how we can grab the sub-images from the atlas we created before, as you can see it’s pretty straightforward, so let’s move on.
We still need to create the actual animation, to do so, we need to create an action, this is how we animate things in SpriteKit. Add the following lines at the end of the “didMoveToView” method:
let textures = [m1, m2, m3, m4, m5, m6, m7, m8] let meleeAnimation = SKAction.animateWithTextures(textures, timePerFrame: 0.07) sprite.runAction(SKAction.repeatActionForever(meleeAnimation))
As you can see, we grouped the images in an array, we then create an action that animates an object using the array of images, the timePerFrame parameter that was determined by trail and error, feel free to try your own values. Finally, we tell our robot sprite to the action that we created, we added the “SKAction.repeatActionForever” action for convenience, this way we can see our animation all the time.
Run the application now, you should be able to see an awesome robot attack with his awesome sword!
You can get the final project here.
Conclusion
We’ve learned a ton regarding sprites so far, we start with the basics, first getting a project setup and adding our assets to it, then we displayed our very first sprite, we created our first atlas using Xcode, and then we took everything together and created an animation showing really cool melee attack that our robot can now perform.
I really hope you enjoyed this tutorial, and I want to wrap up by giving you a challenge. You probably noticed that in the “RobotAnimations.atlas” folder, there is another set of images for a jump animation, I want you to create animation giving the robot the ability to jump, and don’t forget to share it with us.
Stay tuned for more!