http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners
This post is also available in: Japanese
Note from Ray: Congratulations, you guys did it! By helping to spread the word about the iOS 7 Feast, you guys unlocked the first iOS 7 tutorial in less than 15 minutes! :]
Sprite Kit is an exciting new framework for making 2D games that comes built-in to iOS 7. It has sprite support, support for cool special effects like videos, filters, and masking, an integrated physics library, and a lot more.
iOS 7 comes with a great Sprite Kit sample project called Adventure that you should definitely check out. However, the game is a bit complicated and sometimes you just want to start with something as simple as possible. That’s what this tutorial is all about!
In this Sprite Kit tutorial for beginners, you will learn how to create a simple and fun 2D game for your iPhone, from start to finish. If you’ve followed our Simple Cocos2D game tutorial, the game might look familiar ;]
Before getting started be sure to install the latest version of Xcode (5.X) which contains support for Sprite Kit and iOS 7.
You can either follow along with this tutorial, or just jump straight to the sample project at the end. And yes. There will be ninjas.
Before you get started, I just want to point out that Sprite Kit isn’t the only option for you to make 2D games on iOS, and it has several pros and cons you should be aware of.
I thought it would be helpful to take a step back and look at the four most popular options for making games on iOS and their pros and cons.
Sprite Kit Pros
Sprite Kit Cons
After this a lot of you may be thinking, “Well, which 2D framework should I choose?”
The answer that depends on what your goals are. Here’s my 2c:
So after reading all this, if you think Sprite Kit might be what you’re looking for, keep reading and we’ll get you started!
Let’s start by getting a simple Hello World project up and running by using the Sprite Kit Game template that comes built in to Xcode 5.
Start up Xcode, select File\New\Project, choose the iOS\Application\SpriteKit Game template, and clickNext:
Enter SpriteKitSimpleGame for the Product Name, iPhone for Devices, and click Next:
Choose somewhere on your drive to save the project, and click Create. Then click the play button to run the project as-is. You should see the following:
Just like Cocos2D, Sprite Kit is organized into the concept of scenes, which are kind of like “levels’ or “screens” for a game. For example, you might have a scene for the main gameplay area, and another scene for the world map between levels.
If you take a look at your project, you’ll see the template has already created a scene for you by default –MyScene. Open MyScene.m and you’ll see that it contains some code to put a label on the screen, and add a rotating spaceship when you tap somewhere.
In this tutorial, you’ll mainly be working within MyScene. But before you begin, you have to make a few tweaks because this game needs to run in landscape instead of portrait.
First, open your target setting by clicking your SpriteKitSimpleGame project in the Project Navigator, selecting the SpriteKitSimpleGame target. Then, in the Deployment Info section, uncheck Portrait so onlyLandscape Left and Landscape Right are checked, as shown below:
Build and run your project, and all seems to work:
However, all is not as it seems. Let’s try adding the ninja to the game to see why.
First, download the resources for this project and drag them into your Xcode project. Make sure that “Copy items into destination group’s folder (if needed)” is checked, and that your SpriteKitSimpleGame target is selected.
Next, open MyScene.m and replace the contents with the following:
|
Let’s go over this step-by-step.
Build and run, and…
Yowza! The screen is white, but the ninja is nowhere to be seen. You may think that this is by design (because after all, this is a ninja we’re talking about), but there’s actually a problem going on here.
If you look at the console output, you’ll see the following:
|
So our scene thinks its width is 320 and its height is 568 – but actually it’s the opposite!
To see what’s happening here, take a look at ViewController.m‘s viewDidLoad method:
|
This creates the scene with a size as the bounds of the view. However, when viewDidLoad
is called, this is before the view has been added to the view hierarchy and hence it hasn’t responded to layout changes yet. So the view bounds might not be correct yet, and this probably isn’t the best time to start up the scene.
Note: For more details, check out this great explanation by Rob Mayoff.
The solution is to move the start up code to a later point in the process. Replace viewDidLoad with the following:
|
Build and run, and viola – ladies and gentlemen, the ninja has entered the building!
Now that you know the coordinates are working correctly, you’ll put the ninja where he belongs – on the left side toward the middle. To do this, switch back to MyScene.m and replace the line that sets the ninja’s position with the following:
|
Next you want to add some monsters into your scene for your ninja to combat. To make things more interesting, you want the monsters to be moving – otherwise there wouldn’t be much of a challenge! So let’s create the monsters slightly off screen to the right, and set up an action for them telling them to move to the left.
Add the following method to MyScene.m:
|
I’ve spelled out things in a verbose manner here to make things as easy to understand as possible. The first part should make sense based on what we’ve discussed so far: you do some simple calculations to determine where you want to create the object, set the position of the object, and add it to the scene the same way you did for the player sprite.
The new element here is adding actions. Just like in Cocos2D, Sprite Kit provides a lot of extremely handy built-in actions, such as move actions, rotate actions, fade actions, animation actions, and more. Here you use three actions on the monster:
moveTo:
action perform first, and once it is complete perform the removeFromParent:
action.One last thing before you go. You need to actually call the method to create monsters! And to make things fun, let’s have monsters continuously spawning over time.
Sprite Kit does not have the ability to configure update callbacks every X seconds like Cocos2D does. It also does not pass in the delta time since the last update into the method (shocking, I know!)
However, you can mimic this behavior with a small bit of code. First add these properties to the private interface in MyScene.m:
|
You will use lastSpawnTimeInterval
to keep track of the time since you last spawned a monster, andlastUpdateTimeInterval
to keep track of the time since the last update.
Next, you’ll write a method that will be called every frame with the time since the last update. This won’t be called by default – you’ll have to write a separate method to call this, which you’ll do next.
|
Here you simply add the time since the last update to the lastSpawnTimeInterval
. Once it is greater than one second, you spawn a monster and reset the time.
Finally, add this method to call the above:
|
The update:
method will be called automatically by Sprite Kit each frame.
This code actually comes from Apple’s Adventure sample. It passes in the current time, and you do some calculations to determine the time since the last frame. Note it does some sanity checking so that if an unexpectedly large amount of time has elapsed since the last frame, it resets the interval to 1/60th of a second to avoid strange behavior.
That’s it! Build and run the project, now you should see monsters happily moving across the screen:
At this point, the ninja is just begging for some action – so let’s add shooting! There are many ways you could implement shooting, but for this game you are going to make it so when the user taps the screen, it shoots a projectile from the player in the direction of the tap.
I want to use a moveTo:
action to implement this to keep things at a beginner level, but in order to use this you have to do a little math. This is because the moveTo:
requires you to give a destination for the projectile, but you can’t just use the touch point because the touch point represents just the direction to shoot relative to the player. You actually want to keep the bullet moving through the touch point until the bullet goes off-screen.
Here’s a picture that illustrates the matter:
So as you can see, you have a small triangle created by the x and y offset from the origin point to the touch point. You just need to make a big triangle with the same ratio – and you know you want one of the endpoints to be off the screen.
To run these calculations, it really helps if you have some basic vector math routines you can call (like methods to add and subtract vectors). However, Sprite Kit doesn’t have any by default so you’ll have to write your own.
Luckily they are very easy to write. Add these functions to the top of your file, right before the implementation:
|
These are standard implementations of some vector math functions. If you’re confused about what’s going on here or are new to vector math, check out this quick vector math explanation.
Next, add a new method to the file:
|
There’s a lot going on here, so let’s review it step by step.
locationInNode:
and previousLocationInNode:
methods. These let you find the coordinate of a touch within a SKNode’s coordinate system. In this case, you use it to find out where the touch is within the scene’s coordinate system.rwNormalize
. This will make it easy to make a vector with a fixed length in the same direction, because 1 * length = length.moveTo:
and removeFromParent
actions like you did earlier for the monster.Build and run, and now your ninja should be able to fire away at the oncoming hordes!
So now you have shurikens flying everywhere – but what your ninja really wants to do is to lay some smack down. So let’s add in some code to detect when your projectiles intersect your targets.
One of the nice things about Sprite Kit is it comes with a physics engine built right in! Not only are physics engines great for simulating realistic movement, but they are also great for collision detection purposes.
Let’s set up the game to use Sprite Kit’s physics engine to determine when monsters and projectiles collide. At a high level, here’s what you’re going to do:
Now that you understand the battle plan, it’s time to put it into action!
Start by adding these two constants to the top of MyScene.m:
|
This is setting up the two categories you’ll need in a bit – one for the projectiles and one for the monsters.
Note: You may be wondering what the fancy syntax is here. Note that the category on Sprite Kit is just a single 32-bit integer, and acts as a bitmask. This is a fancy way of saying each of the 32-bits in the integer represents a single category (and hence you can have 32 categories max). Here you’re setting the first bit to indicate a projectile, and the next bit over to represent a monster.
Next, inside initWithSize add these lines after adding the player to the scene:
|
This sets up the physics world to have no gravity, and sets the scene as the delegate to be notified when two physics bodies collide.
Inside the addMonster method, add these lines right after creating the monster sprite:
|
Let’s go over what this does line by line.
monsterCategory
you defined earlier.contactTestBitMask
indicates what categories of objects this object should notify the contact listener when they intersect. You choose projectiles here.collisionBitMask
indicates what categories of objects this object that the physics engine handle contact responses to (i.e. bounce off of). You don’t want the monster and projectile to bounce off each other – it’s OK for them to go right through each other in this game – so you set this to 0.Next add some similar code to touchesEnded:withEvent:, right after the line setting the projectile’s position:
|
As a test, see if you can understand each line here and what it does. If not, just refer back to the points explained above!
As a second test, see if you can spot two differences. Answer below!
Solution Inside: What Are the Differences? | Show |
---|---|
Next, add a method that will be called when the projectile collides with the monster. Note that nothing calls this automatically, you will be calling this later.
|
All you do here is remove the projectile and monster from the scene when they collide. Pretty simple, eh?
Now it’s time to implement the contact delegate method. Add the following new method to the file:
|
Since you set the scene as the contactDelegate
of the physics world earlier, this method will be called whenever two physics bodies collide (and their contactTestBitMask
s are set appropriately).
There are two parts to this method:
One last step – mark the private interface as implementing SKPhysicsContactDelegate
to make the compiler happy:
|
Give it a build and run, and now when your projectiles intersect targets they should disappear!
You’re pretty close to having a workable (but extremely simple) game now. You just need to add some sound effects and music (since what kind of game doesn’t have sound!) and some simple game logic.
Sprite Kit does not come with an audio engine like Cocos2D does, but the good news it does come with a simple way to play sound effects via actions, and that you can play background music pretty easily with AVFoundation.
You already have some cool background music I made and an awesome pew-pew sound effect in your project, from the resources for this tutorial you added to your project earlier. You just need to play them!
To do this, add the following import to the top of ViewController.m:
|
This demonstrates the new modules feature in iOS 7 – basically by using the new @import keyword, you can bring in the header files (and library) for a framework in a single, efficient step. To learn more about this, check out Chapter 10 in iOS 7 by Tutorials, What’s New with Objective-C and Foundation.
Next add a new property and private interface:
|
Add this code to viewWillLayoutSubviews, right after the call to [super viewWillLayoutSubviews]
:
|
This is some simple code to start the background music playing with endless loops.
As for the sound effect, switch back to MyScene.m and add this line to the top of touchesEnded:withEvent::
|
Pretty handy, eh? You can play a sound effect with one line!
Now, let’s create a new scene and layer that will serve as your “You Win” or “You Lose” indicator. Create a new file with the iOS\Cocoa Touch\Objective-C class template, name the class GameOverScene, make it a subclass of SKScene, and click Next and then Create.
Then replace GameOverScene.h with the following code:
|
Here you imported the Sprite Kit header and marked that you are implementing a special initializer that takes a parameter of whether the user won the level or not in addition to the size.
Then replace GameOverLayer.m with the following code:
|
There are four parts to this method:
won
parameter, sets the message to either “You Won” or “You Lose”.runBlock
action to run some arbitrary code.presentScene:transition:
method on the self.view
property.So far so good, now you just need to set up your main scene to load the game over scene when appropriate.
To do this, first add an import for the new scene at the top of MyScene.m:
|
Then inside addMonster, replace the last line that runs the actions on the monster with the following:
|
This creates a new “lose action” that displays the game over scene when a monster goes off-screen. See if you understand each line here, if not refer to the explanation for the previous code block.
Also, another pop-quiz for you: why do you run the loseAction
before actionMoveDone
? Try reversing them to see what happens if you don’t know.
Solution Inside: Why is Lose Action First? | Show |
---|---|
Now you should handle the win case too – don’t be cruel to your players! :] Add a new property to the private interface:
|
And add this to the bottom of projectile:didCollideWithMonster::
|
Go ahead and give it a build and run, and you should now have win and lose conditions and see a game over scene when appropriate!
And that’s a wrap! Here is the full source code for this Sprite Kit tutorial for beginners.
I hope you enjoyed learning about Sprite Kit and are inspired to make your own game!
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 level editor.
If you have any questions or comments about this tutorial, please join the discussion below!