How to Make a Platform Game Like Super Mario Brothers – Part 1

This is a blog post by iOS Tutorial Team member Jacob Gundersen, an indie game developer who runs the Indie Ambitions blog. Check out his latest app – Factor Samurai! For many of us, Super Mario Brothers was the first game that made us drop our jaws in gaming excitement. Although video games started with […] By Jake Gundersen.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 5 of this article. Click here to view the first page.

Loading the TMXTiledMap

I’m going to assume you’re familiar with how tile maps work. If you aren’t, you can learn more about them in this tutorial.

Let’s take a look at the level. Start up your Tiled map editor (download it if you don’t have it already) and open level1.tmx from your project directory. You’ll see the following:

A platformer game level made with Tiled

If you look in the sidebar, you’ll see that there are three different layers:

  • hazards: This layer contains the things the Koala needs to avoid touching to stay alive (gulp).
  • walls: This layer contains tiles the Koala cannot move through, which mostly consist of floor tiles.
  • background: This layer contains things that are there for aesthetics only, such as clouds or hills.

Now time to code! Open up GameLevelLayer.m and add the following after the #import but before the @implementation:

@interface GameLevelLayer() 
{
  CCTMXTiledMap *map;
}

@end

This adds a private instance variable for the tile map into your class.

Next you’ll load this map into your layer by loading it in the init section. Add the following code to init:

CCLayerColor *blueSky = [[CCLayerColor alloc] initWithColor:ccc4(100, 100, 250, 255)];
[self addChild:blueSky];

map = [[CCTMXTiledMap alloc] initWithTMXFile:@"level1.tmx"];
[self addChild:map];

First, you add a background color (a CCLayerColor) to the layer, which will be the blue sky. The next two lines of code simply load the tile map (a CCTMXTiledMap) and add it to the layer.

Next, in GameLevelLayer.m, add the import for Player.h:

#import "Player.h"

Still in GameLevelLayer.m, add the following instance variable to the @interface section:

Player * player;

Then add the Koala to the level with the following code in the init method:

player = [[Player alloc] initWithFile:@"koalio_stand.png"];
player.position = ccp(100, 50);
[map addChild:player z:15];

This code loads the Koala sprite object, gives it a position, and adds it to the map object.

You may be wondering why you added the Koala to the map object instead of the layer. Well, you want to control exactly which TMX layers are in front of and behind the Koala sprite, so the Koala needs to be a child of the map. You want your hero Koalio in front, so you give him a Z-order of 15. Also, this makes it so that if you scroll the tile map, the Koala still stays in the same relative position within the tile map.

OK, let’s check it out! Build and run and you should see the following:

It looks like a game, but Koalio is defying gravity! It’s time to kiss him goodbye and bring him down – with a physics engine :]

The Gravity of Koalio’s Situation

The gravity force is always on!

To build a physics simulation, you could write a complex set of branching logic that takes the Koala’s state into account and decides which forces to apply based on that state. But, this would quickly become very complicated — and it isn’t really how physics works. In the real world, gravity is always pulling things towards the earth. So you’ll add the constant force of gravity to the Koala in every frame.

Other forces don’t just switch on and off. In the real world, a force is applied to an object and the momentum continues to move the object through space until some other force acts on that object to change the momentum.

For example, a vertical force like a jump doesn’t turn gravity off; it momentarily overcomes gravity, but gravity slows the ascent, and ultimately brings the object back to the ground. Similarly, a force that pushes an object is countered by friction, which gradually slows down the object until it stops.

This is how you’ll model your physics engine. You won’t constantly check whether your Koala is on the ground and decide whether to apply gravity; gravity will always be applied in this world.

Playing God

I control all the forces!

The logic of your physics engine will mean that when a force is applied to an object, the object will continue to move until another force counteracts it. When Koalio walks off a ledge, he’ll continue to move down at an accelerating rate until he collides with something else. When you move Koalio, he won’t stop moving as soon as you stop applying force; friction will slow him down gradually until he stops.

As you proceed with your platform game, you’ll see that this logic will make it easier to handle complex situations, such as an ice floor where the Koala doesn’t stop on a dime, or a free-fall over a cliff. This model of cumulative forces will make for a fun, dynamic-feeling game.

It will also make the implementation easier, because you won’t have to constantly query the state of your objects – they will just follow the natural laws of your world and their behavior will emerge from the application of those laws!

Sometimes, you do get to play God! :]

The Law of the Land: CGPoints and Forces

Let’s define a few terms:

  • Velocity describes how fast an object is moving in a given direction.
  • Acceleration is the rate of change in velocity – how an object’s speed and direction change over time.
  • A force is an influence that causes a change in speed or direction.

In a physics simulation, a force applied to an object will accelerate that object to a certain velocity, and that object will continue moving at that velocity, until acted upon by another force. Velocity is a value that persists from one frame to the next and only changes by the application of new forces.

You’re going to be representing three things with CGPoint structures: velocity (speed), force/acceleration (change in speed), and position. There are two reasons for using CGPoint structures:

  1. They’re 2D. Velocity, force/acceleration, and position are all 2D values for a 2D game. “What?” you might say. “Gravity only acts in one dimension!” However, you could easily imagine a game with changing gravity where you’d need the second dimension. Think Super Mario Galaxy!
  2. It’s convenient. By using CGPoints, you can rely on the various built-in functions within Cocos2D. You’ll be making heavy use of functions such as ccpAdd (add two points), ccpSub (subtract them), and ccpMult (multiply a point by a float to scale it up or down). This will make your code much easier to write — and debug!

Your Koala object will have a velocity variable that will be acted upon in each frame by a number of forces, including gravity, forward/jumping forces supplied by the user, and friction, which will slow and stop the Koala.

In each frame, you’ll add all these forces together, and the accumulated force that results will be added to the previous velocity of the Koala object. That will give you the current velocity. The current velocity will be scaled down to match the fractional time amount between each frame, and finally, that scaled value will be used to move the Koala’s position for that frame.

Note: If any of this still sounds confusing, Daniel Shiffman wrote an excellent tutorial on vectors that explains the accumulation of forces structure that you’ll be using. The tutorial is designed for Processing, a language for creative designers similar to Java, but the concepts are applicable in any programming language. It’s a great and accessible read and I highly recommend you check it out!

Let’s start with gravity. Set up the run loop, where you’ll be applying these forces. In the GameLevelLayer.m, add the following to init before the close of the if block:

[self schedule:@selector(update:)];

Then add the method to the class:

-(void)update:(ccTime)dt 
{
    [player update:dt];
}

Next open up Player.h and add modify it to look like the following:

#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface Player : CCSprite 

@property (nonatomic, assign) CGPoint velocity;

-(void)update:(ccTime)dt;

@end

Next add the implementation to Player.m:

#import "Player.h"

@implementation Player

@synthesize velocity = _velocity;

// 1
-(id)initWithFile:(NSString *)filename 
{
    if (self = [super initWithFile:filename]) {
        self.velocity = ccp(0.0, 0.0);
    }
    return self;
}

-(void)update:(ccTime)dt 
{

    // 2
    CGPoint gravity = ccp(0.0, -450.0);
    
    // 3
    CGPoint gravityStep = ccpMult(gravity, dt);

    // 4
    self.velocity = ccpAdd(self.velocity, gravityStep);
    CGPoint stepVelocity = ccpMult(self.velocity, dt);
    
    // 5
    self.position = ccpAdd(self.position, stepVelocity);
}

@end

Let’s go through the above code section by section.

  1. Here you created a new init method to initialize the velocity variable to 0.0.
  2. Here you declared the value of the gravity vector (vector meaning the change in position). For each second in time, you’re accelerating the velocity of the Koala 450 pixels towards the floor. If the Koala starts from a standstill, at the one second mark he’ll be moving at 450 pixels/second, at two seconds he’ll be moving at 900 pixels/second, and so forth. Clear enough!
  3. Here, you used the ccpMult to scale the acceleration down to the size of the current timestep. Recall that ccpMult multiplies a CGPoint’s values by a float value, and returns the CGPoint result. Even when you’re faced with a variable frame rate, you’ll still get consistent acceleration.
  4. Here once you’ve calculated the gravity for the current step, you add it to your current velocity. With the new velocity you’ve calculated, you then got the velocity for a single timestep. Again, you’re doing these calculations in order to get consistent velocity, no matter what the frame rate is.
  5. Finally, with the velocity you calculated for this single step, you use the ccpAdd function to get the updated position for the Koala.

Congratulations! You are well on your way to writing your first physics engine! Build and run now to see the result!

Whoops — Koalio is falling through the floor! Let’s fix that up.

Jake Gundersen

Contributors

Jake Gundersen

Author

Over 300 content creators. Join our team.