Building my first iOS game with Sprite Kit

Dylan Shine
14 min readJun 12, 2015

--

Ever since I purchased my first iPhone, I’ve always wanted to learn how to build my own games. Over the past week, I took the time to read the first few chapters of iOS Games by Tutorial by the team over at raywenderlich.com. The book aims to teach you Sprite Kit, a framework built into Xcode that helps you build 2D games for iOS and OSX. By the end of building the books first game, I wanted to try to build my own from scratch…this is my story.

This post is going to outline my step by step process of how I ended up building a game called Colorpillar. I’m new to game development (and iOS development in general) so by no means do I think that my code follows best practices for how to build a game with Sprite Kit. Here is the link to the repository.

First lets understand how Colorpillar is going to work. A player is going to guide a colorpillar around the screen trying to eat food that matches the current color of its head. Food will randomly spawn on the screen with a random color. The color of the colorpillar will change after ever piece of food he eats. If the colorpillar eats a matching piece of food, the colorpillar will grow. If the colorpillar eats a piece of food that isn’t the same color as it’s head, the player loses a life. If the player loses all three lives, crashes in a wall, or hits it’s own body, the player loses the game. Sounds simple, so lets get started.

First open up Xcode and create a new project. Under the iOS Application section, select the Game template, set your project options to use Sprite Kit and Objective-C, and save the project to someplace safe.

Before we start getting into the code, under the projects General settings, make sure that the device orientation is set to portrait and nothing else.

When we created our project, Xcode generated a bunch of files for us. If you’re familiar with general iOS app development, you’ll notice that there is still an AppDelgate, ViewController and Storyboard. However in addition to those files, we have a GameScene .h and .m file. Our GameScene class inherits from Sprite Kits SKScene class. According to the Apple iOS Developer documents:

“An SKScene object represents a scene of content in Sprite Kit. A scene is the root node in a tree of Sprite Kit nodes (SKNode). These nodes provide content that the scene animates and renders for display. To display a scene, you present it from an SKView object.”

Great, so now that we know where all of our content is supposed to go, we can start adding some. Before we start creating our game objects though, we need to update our GameViewController.m file. Delete the viewDidLoad method and replace it with the following code:

Code Breakdown:

  1. We instantiate a new SKView by casting our current view
  2. If the SKView exists, set the showFPS, showsNodeCount and ignoresSiblingOrder to YES. This simply shows the frame rate and the count of nodes that are currently on the screen in the lower right corner of our device.
  3. Instantiate our GameScene by passing in the size of our SKView
  4. Call SKViews present scene method

The main reason why we change viewDidLoad to viewWillLayoutSubviews is because this is the first method the ViewController calls where we have the correct bounds for the device, and therefore we can set our SKView to the correct size.

Now that that’s settled, head over to the GameScene.m file and delete all of the default code Xcode generated. In order to build our game, we’re going to need to define the objects and properties that will make up our game. Add the following private variables to the top of your file:

Code Breakdown:

  1. SKSpriteNode is a node that will be added to the SKScene. The colorpillar, food and body will all be represented as SKSpriteNodes.
  2. The currentDirection is a NSString that will represent the current SKAction the colorpillar is currently running. The reason I use an NSString instead of a SKAction is because it’s easier for me to compare equality. The currentDirection will be equal to a key in the directions dictionary whose value will be an SKAction. I’ll get in SKActions a little bit later.
  3. bodyNodes is a NSMutableArray that will hold all of our SKSpriteNode body parts. If you’re familiar with how Sprite Kit works, this might seem a little unorthodox, but it will come in handy later.
  4. currentColor is a UIColor that will be used to change the color of the colorpillar and allow what food he can eat at any given time.
  5. colors is a NSArray that will store three UIColors that will make up the colorpillar and food colors
  6. lives is the number of lives the player will have
  7. scoreBoard is a SKLabelNode that will show the player how many food nodes they’ve collected and how many lives they have left
  8. The reason I am prefixing an underscore for each of the variable names is to denote that it is a private variable for the scene

We need to create an initWithSize:(CGSize)size that will be used to create our SKScene:

Code Breakdown:

  1. We set the colors red, blue and green to the NSArray literal

2. The directions dictionary will be used to move the colorpillar. Each direction has a value of [SKAction moveBy:(CGVector) duration:(NSTimeInterval)] . The first argument takes a CGVector which is represented as a dx, dy coordinate. If you’re not familiar with vectors take a look at this article. The second argument takes an NSTimeInterval represented by seconds. So, if the colorpillar wants to move @”up”, it will go 0 x coordinates and 3 y coordinates in 0.3 seconds. I’ll expand on this later.

3. Set our lives to 3

4. Instantiate an NSMutableArray that will contain our body nodes

5. Instantiate a new SKSpriteNode with the [SKSpriteNode spriteNodeWithColor(UIColor *) size:(CGSize)] method. This method takes two arguments, a UIColor and a CGSize. We pass in blackColor to make the node black and a CGSize of (20,20). By default SKSpriteNodes created with this method are rectangular, so a size of (20,20) would make a perfect square.

6. Set the zPosition to 100; If you’re familiar with zIndexes in CSS, this property simply increases the stack order of the nodes. The node with a higher zPosition that another would look to be on top of it if they were at the same position.

7. We set the background color of the scene to white

8. Add the colorPillar to the scene. In order for your nodes to appear on scene, you need to add them to it using the add child method.

If you run/build your project, you should see a black square in the middle of the iPhone simulator.

Great, you’ve added your first SKSpriteNode to the scene but it’s kind of boring. Lets get our colorpillar to move about the screen.

Add the following two methods to your GameScene.m file:

In Sprite Kit, every game has a game loop that call your SKScenes methods to change the state of the game.

The update method we added evaluates all the actions on the scenes nodes. On average, the update method is called every 15–30 milliseconds; the variance comes from your devices processing speed.

The moveColorpillar method calls runAction on the colorpillar node. This method takes an SKAction and operates on the node accordingly. Since we stored those four SKActions in our directions dictionary, the colorpillar will move in whatever direction the current direction is set to. If you run the project, you’ll notice the colorpillar flies off of the screen and never returns, lets fix this.

Add the following code to your GameScene.m file:

First the touchesEnded method does exactly what you think it would:

  1. Creates a UITouch object
  2. Creates a CGPoint based on where the touch happened on the screen. You can imagine the screen as a coordinate system, where (0,0) is bottom left and (screen.width,screen.height) is top right.

3. Call the turnColorpillarToward method passing in the CGPoint of the touch

The turnColorpillarToward method on the other hand is a little more tricky. We don’t want to player to turn the colorpillar in on it self which would cause them to lose the game, so if the colorpillar is going up, it should only be able to go left or right. To prevent this, we write two conditional statements for each case:

EXAMPLE:

  1. Check what the current direction the colorpillar is moving

2a. If the direction is @”up” or @”down”, check if the touch location X is less than or greater than the current colorpillar position

2b. If the direction is @”left” or @”right”, check if the touch location Y is less than or greater than the current colorpillar position

3. Set the current position accordingly

Run your project and voila, you’ll notice that you can guide the colorpillar by touching the screen. Now that we have the colorpillar moving, lets spawn some food for it to eat.

In order to get the food nodes to spawn at random points on the screen, we’re going to need a create a method that will return us random CGFloats that are in the bounds of our screen. With a quick trip to our friends over at Stack Overflow, I was able to find a method that would do just that. At the top of your file, right above @implementation GameScene, add the following method.

You don’t need to know what this method does behind the scene, just know it returns a random CGFloat that exists in a specified range. Now that we can produce random points on our screen, lets implement a method that will create the food SKSpriteNodes.

Code Breakdown:

  1. Similar to our colorpillar SKSpriteNode, we instantiate a new SKSpriteNode, food, with the greenColor and a CGSize of (20,20)
  2. We set the position of the food to a random position using the static inline method we just added to our file.
  3. We create a larger CGRect frame and ask if the frame of the food node intersects with the frame of the colorpillar. The reason why we added this conditional statement is to prevent a piece of food from randomly popping up in front of or on top of our colorpillar. It would be unfair if the player lost a life because of a rogue piece of food.
  4. We set the name of food to @”food”: The main reason why we do this is so we can iterate through all of our food nodes that are added to the scene. Sprite Kit allows to iterate through our SKSpriteNodes with the enumerateChildNodesWithName:(NSString *)usingBlock: ^(SKNode *node, BOOL *stop)block method. I’ll go more into this method later, but notice that in order to iterate, we must pass in a name in the form of an NSString.
  5. We set the nodes xScale and yScale to 0, this makes the node appear invisible.
  6. Add the node to the scene
  7. We then create a 4 SKActions and run them in a sequence. The first SKAction [SKAction scaleTo:1.0 duration:0.5] scales our node to xScale and yScale 1 (its default size) over the course of a half second. We then create another SKAction [SKAction scaleTo:1.0 duration:0.5] which does the exact opposite. The SKAction [SKAction waitForDuration:7] does exactly what you think it does, waits for 7 seconds. Finally the [SKAction removeFromParent] removes the node from the parent, which in this case would be our SKScene that we just added it to. The SKAction class has sequences which allows us to run our actions on nodes in you guessed it, a sequence. So the player will see the piece of food pop up from the scene, wait 7 seconds to be collected, shrink itself back down, and then remove itself from the scene.

Great, we now have a method that can create random pieces of food, but where should we call it? If we added it to the update method, the method would be called approximately every 20 milliseconds. A new random piece of food every 20 milliseconds would make the game next to impossible to play, so lets update our initWithSize method using SKActions repeatActionForever method.

Passing in our scene, we call the SKAction repeatActionForever which takes in another SKAction. As our second SKAction, we send in a sequence, the first action being the spawnFood method we just wrote using SKActions [SKAction performSelector:(SEL) onTarget:(id)], and the second action we call is a waitForDuration method. Essentially what’s happening is that a food node will randomly spawn on the scene every second. Run the project to see this in action.

This game is called Colorpillar, and so far we only have two colors, so lets fix that. Add the following two methods to our GameScene.m file.

These two methods are pretty straight forward. The first method makeRandomColor simply returns a random UIColor from our colors array we defined earlier. The setGameColor sets the currentColor and colorpillars color to a random color using the makeRandomColor method.

We then need to update the initWithSize method where we create our colorpillar and in the spawnFood method where we create our food nodes.

Alright, we have a moving colorpillar and food everywhere, but still our colorpillar has no way of eating the food to grow. Lets make that happen.

In order for our colorpillar to grow, we need to do a few things. We first need to check when the colorpillar collides with a food node. After it collides, we need to check whether the food nodes color matches the current color of the colorpillar. If it does, we need to append a body node to the colorpillar and have it follow it around for the rest of the game. Write out the following two methods and I’ll explain them in detail below:

Code Breakdown:

  1. Using the enumerateChildNodesWithName:(NSString *)usingBlock: ^(SKNode *node, BOOL *stop)block that I mentioned earlier, we iterate through all of the scenes children who have the name @”food”.
  2. If the colorpillar and the food node intersect, and they are the same color, we remove the food from the scene, create a new body node with that has the same size and color and set its zPosition to 100
  3. We then call the setColor method that changes the games currentColor and colorpillars color to a random color…phew that was a lot of colors there.
  4. Then we do something interesting here…if the size of bodyNodes is 0 (the colorpillar hasn’t eaten any food yet) we set the position of the new body node to the position of the colorpillar. If the colorpillar already has body nodes, we set the new body nodes position to the colorpillars last body node. Then depending on the current direction of the colorpillar, we set the position again to an offset of the body nodes height.

Example: If the currentDirection is @”up”, we would set the new body nodes y coordinate -20(the height of the node)… you can imagine how this would work in the other three directions.

5. We then add the new body node to the bodyNodes array and the scene

6. However if the color of the colorpillar and the food node don’t match, we remove the food node from the scene, subtract one life from the player, and reset the color using the setGameColor method.

Remember when I said that creating a bodyNodes array might seem a bit weird, well here is where it comes in as a life saver. We need each body node to follow the body node that is in front of it, and of course the first node to follow the colorpillar. To accomplish this we simply iterate through our bodyNodes array and use the [SKAction moveTo:(CGPoint) duration: NSTimeInterval)] method.

We then add our followColorpillar method to our update method and the checkFoodCollisions method to a new method called didEvaluateActions. According to the Apple Developer Docs, didEvaluateActions:

“Performs any scene-specific updates that need to occur after scene actions are evaluated.”

If you build your project, your colorpillar can now successfully eat the spawning food and grow. That’s good and all, but the player still can’t do a crucial thing that is built into every game, lose.

As I said in the beginning, the player should lose if one of three things happens, the colorpillar loses all of its lives, crashes into a wall, or runs into its own body.

The checkBodyCollisions method checks to see if the head intersects with any of the body nodes excluding the first and the last. The reason I set it up this way is because the player would lose a life if the they turned (by touching the first node) and when consuming a node. The new body node sometimes has to pass through the entire body to get to its position, which could accidentally collide with the colorpillar.

In the boundsCheck method, the game simply track the head node and makes sure it stays within the bounds of the screen.

And finally the checkIfLost method checks if any of the three ways of losing have happened. If the conditional is triggered, we remove all of the children and the food spawning action from the scene, reset the background color to red, and set two SKLabelNodes that read “Game Over” and the players score. At the end of the method we create a waitForDuration and runBlock action. The runBlock action creates a new GameScene, creates an SKTransition (which allows us to transition from scene to scene) and calls the presentScene passing in our new scene and transition. Don’t forget to add it to your didEvaluateActions method.

Finally it would be really nice if the player could see their score and how many lives they had left while playing.

In the initWithSize method, we create another SKLabelNode, set its properties so that it is positioned at the top and center of the screen, and add it to the scene.

scoreUpdate simply sets the text of the SKLabelNode to the current count of bodyNodes and the amount of lives. Then within the didEvaluateActions, we add scoreUpdate.

And there we have it, my first ever game built with Sprite Kit. If you have any questions or suggestions, please feel free to leave them in the comments. I hope you enjoyed!

Best,

Dylan Shine

--

--