How to Make a Line Drawing Game with Sprite Kit
Learn how to make a line drawing game like Flight Control and Harbor Master in this Sprite Kit tutorial! By Jean-Pierre Distler.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How to Make a Line Drawing Game with Sprite Kit
50 mins
- Getting Started
- Adding the Background… and a Pig!
- Moving the Sprite
- Responding to Touches
- Drawing Lines
- Continuous Movement
- Rotating the Sprite
- Animating the Sprite
- Your Gameplay Strategy
- Completing the Scene
- Spawning Pigs
- Detecting Collisions
- Adding Physics Bodies
- Feeding the Pigs
- Finishing the Game
- Game Over: When Pigs Collide
- Adding Polish
- Where to Go From Here?
Continuous Movement
Actually, the pig stops moving after it reaches the last waypoint. For Hogville, it makes more sense and will be more challenging if the pigs keep moving. Otherwise, you could simply draw a path to the pigs straight to their pens and the game would be over!
Let's correct this. Open Pig.m and add the following code at the end of move:
:
else {
newPosition = CGPointMake(currentPosition.x + _velocity.x * [dt doubleValue],
currentPosition.y + _velocity.y * [dt doubleValue]);
}
This code simply continues to move the pig with its most recently calculated velocity when it runs out of waypoints. Remember, velocity includes both direction and speed.
Now find this line inside move:
:
self.position = newPosition;
Move the above line to the end of the method so that after the if-else
statements.
Build and run, and watch your pig moving and moving and moving... until you can’t see it anymore. This little piggy went off screen!
What you need is a method to check if the pig is about to leave the screen and if so, switch its direction.
Also in Pig.m, add this method:
- (CGPoint)checkBoundaries:(CGPoint)point {
//1
CGPoint newVelocity = _velocity;
CGPoint newPosition = point;
//2
CGPoint bottomLeft = CGPointZero;
CGPoint topRight = CGPointMake(self.scene.size.width, self.scene.size.height);
//3
if (newPosition.x <= bottomLeft.x) {
newPosition.x = bottomLeft.x;
newVelocity.x = -newVelocity.x;
}
else if (newPosition.x >= topRight.x) {
newPosition.x = topRight.x;
newVelocity.x = -newVelocity.x;
}
if (newPosition.y <= bottomLeft.y) {
newPosition.y = bottomLeft.y;
newVelocity.y = -newVelocity.y;
}
else if (newPosition.y >= topRight.y) {
newPosition.y = topRight.y;
newVelocity.y = -newVelocity.y;
}
//4
_velocity = newVelocity;
return newPosition;
}
This looks more complicated than it is, so let’s look more closely:
- First, you assign the current velocity and point to local variables.
- Here you define the important points on the screen. You can use
bottomLeft
to check if the pig is moving off screen from the left or bottom sides andtopRight
to check the top and right sides of the screen. You perform these checks inside the followingif
statements, one for each side of the screen. - The first
if
statement checks thex
value ofnewPosition
. If this value is zero or less, the pig is leaving the screen from the left side. To avoid this, you set the pig'sx
-position to the left boundary—zero—and reverse thex
-component of the velocity so the pig starts moving in the opposite direction. The otherif
statements do the same for the remaining three bounds of the screen. - At the end, you change
_velocity
to whatever value you calculated and then returnnewPosition
.
To make use of this new method, change the last line in move:
from this:
self.position = newPosition;
To this:
self.position = [self checkBoundaries:newPosition];
Build and run your project again and watch the pig bounce off of the screen’s borders. You’ve got yourself a pig pen!
Rotating the Sprite
Before adding the actual gameplay, there are some minor improvements you should make. First, the pig doesn't rotate at all, which looks a bit weird. Like most animals, pigs normally walk facing forward rather than backward or to the side!
Rotate the pig so that it faces the direction it’s moving by adding the following line to the end of move:
in Pig.m:
self.zRotation = atan2f(_velocity.y, _velocity.x) + M_PI_2;
atan2f
returns the angle between the x-axis and the given point. You add M_PI_2
because the pig image you use faces down and the value you receive from atan2f
assumes the image faces to the right. Therefore, by adding M_PI_2
, you rotate the pig by 90° counterclockwise.
Note: If this is too much math for you, check out our open source SKTUtils library. The library includes a ton of helper functions that abstracts common math like this; for example it includes a CGPointToAngle
method that would be helpful here.
Note: If this is too much math for you, check out our open source SKTUtils library. The library includes a ton of helper functions that abstracts common math like this; for example it includes a CGPointToAngle
method that would be helpful here.
Animating the Sprite
Now that the pig faces the direction it's moving, it's time to add a pretty animation. Add the following new instance variable in Pig.m's @implementation
section:
SKAction *_moveAnimation;
Next, go to initWithImageNamed:
and add the following lines directly after the line that creates _wayPoints
:
SKTexture *texture1 = [SKTexture textureWithImageNamed:@"pig_1"];
SKTexture *texture2 = [SKTexture textureWithImageNamed:@"pig_2"];
SKTexture *texture3 = [SKTexture textureWithImageNamed:@"pig_3"];
_moveAnimation = [SKAction animateWithTextures:@[texture1, texture2, texture3] timePerFrame:0.1];
This creates three textures, each of which represents a frame of the animation. The last line creates an SKAction
that animates the pig’s movement using the three textures and stores the action in _moveAnimation. The game will show each frame for 0.1 seconds, resulting in a nice walking animation for the pig.
The last step is to run the animation. In Pig.m, go to move:
and add the following lines at the beginning of the method:
if(![self actionForKey:@"moveAction"]) {
[self runAction:_moveAnimation withKey:@"moveAction"];
}
First, you check if an animation named "moveAction" is already running and add it if there is no such animation. This ensures that the game adds the animation only once. Without this check, you wouldn't see the animation because it would start from the beginning every time you called move:
.
Build and run, and watch your pig animate around the screen as you direct it.
Your Gameplay Strategy
Let’s pause to think about how the gameplay will work and what you need to achieve it.
The basic idea behind Hogville is that pigs will appear at random positions on the left side of the screen and from there, move in random directions. The time between the appearances of each new pig will decrease until it reaches a threshold defined by you.
The player must herd all of these pigs to a trough of food where they can eat and after that, bring them to a barn where they can sleep. If any two pigs collide, the game is over.
Here are the needed steps:
- Add sprites for the food trough and barn.
- Spawn pigs over time.
- Add collision handling.
- Add logic that controls when a pig needs food or is ready to sleep.
- Handle win/lose conditions.
You will go step by step through this list to finish your game. Don't panic—this tutorial is here to guide you!