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

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! Welcome back to our 2-part tutorial series on making a game like Super Mario! In the first part of the series, you learned how to […] By Jake Gundersen.

Leave a rating/review
Save for later
Share

Learn how to make a game like Super Mario!

Learn how to make a game like Super Mario!

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!

Welcome back to our 2-part tutorial series on making a game like Super Mario!

In the first part of the series, you learned how to create a simple, tile-based physics engine that controls how the hero of your game, Koalio, moves around his world.

In this second and final part of the series, you’ll learn how to make Koalio run and jump – the fun part of the game!

You’ll also add collisions with those scary spikey floors, handle winning and losing, and of course add some gratuitous sound effects and music!

This second part is WAY simpler (and shorter) than the first tutorial, a reward for the hard work you put in last time! So turn your coding mojo on, and enjoy!

Moving Koalio Around

The controls you’re going to implement are very simple. There will be forward and jump controls only — much like 1-bit Ninja. If you touch the left half of the screen, Koalio will run forward. Touching the right half of the screen will make Koalio jump.

You heard me right – Koalio can’t move backwards! True Koalas don’t back down from danger.

Since Koalio will be moved forward by the user, rather than by the GameLevelLayer, you need some values that you can check in the Player class to update his forward velocity. Add the following properties to the Player class (don’t forget to synthesize!):

In Player.h:

@property (nonatomic, assign) BOOL forwardMarch;
@property (nonatomic, assign) BOOL mightAsWellJump;

In Player.m:

@synthesize forwardMarch = _forwardMarch, mightAsWellJump = _mightAsWellJump;

Now add the following touch-handling methods to the GameLevelLayer:

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {  
  for (UITouch *t in touches) {
    CGPoint touchLocation = [self convertTouchToNodeSpace:t];
    if (touchLocation.x > 240) {
      player.mightAsWellJump = YES;
    } else {
      player.forwardMarch = YES;
    }
  }
}

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  for (UITouch *t in touches) {
    
    CGPoint touchLocation = [self convertTouchToNodeSpace:t];
    
    //get previous touch and convert it to node space
    CGPoint previousTouchLocation = [t previousLocationInView:[t view]];
    CGSize screenSize = [[CCDirector sharedDirector] winSize];
    previousTouchLocation = ccp(previousTouchLocation.x, screenSize.height - previousTouchLocation.y);
    
    if (touchLocation.x > 240 && previousTouchLocation.x <= 240) {
      player.forwardMarch = NO;
      player.mightAsWellJump = YES;
    } else if (previousTouchLocation.x > 240 && touchLocation.x <=240) {
      player.forwardMarch = YES;
      player.mightAsWellJump = NO;
    }
  }
}

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  
  for (UITouch *t in touches) {
    CGPoint touchLocation = [self convertTouchToNodeSpace:t];
    if (touchLocation.x < 240) {
      player.forwardMarch = NO;
    } else {
      player.mightAsWellJump = NO;
    }
  }
}

These changes should be pretty straightforward. If the user creates a touch event that has an X-coordinate of less than 240 (half the screen), you turn on the forwardMarch boolean for the player. Otherwise (if the location of the touch event is greater than 240), simply turn on the mightAsWellJump boolean.

touchesMoved is a little more complicated, because you only want to flip the boolean values above if the touch crosses mid screen, so you have to calculate the previousTouch location as well. Other than that, you're just checking to see which direction the touch crosses and turning the appropriate boolean on or off. Finally, if the user stops touching the one side of the screen or the other, you want to turn the appropriate boolean value off.

There are a few changes that need to be made to detect touches. First, add this line to init:

	self.isTouchEnabled = YES;

You’ll need to turn on multitouch in AppDelegate.m (so as to detect a touch that directs the player to move forward and to jump at the same time). Add the following line before the [director_ pushScene: [GameLevelLayer scene]]; line:

	[glView setMultipleTouchEnabled:YES];

Now that you are passing the touches through to your player class booleans, you can add some code to the update method so that Koalio can move. Start with the forward movement. Change the update method in Player.m to the following:

-(void)update:(ccTime)dt {
    CGPoint gravity = ccp(0.0, -450.0);
    CGPoint gravityStep = ccpMult(gravity, dt);
    
    CGPoint forwardMove = ccp(800.0, 0.0);
    CGPoint forwardStep = ccpMult(forwardMove, dt); //1
    
    self.velocity = ccpAdd(self.velocity, gravityStep);
    self.velocity = ccp(self.velocity.x * 0.90, self.velocity.y); //2
    
    if (self.forwardMarch) {
        self.velocity = ccpAdd(self.velocity, forwardStep);
    } //3
    
    CGPoint minMovement = ccp(0.0, -450.0);
    CGPoint maxMovement = ccp(120.0, 250.0);
    self.velocity = ccpClamp(self.velocity, minMovement, maxMovement); //4
    
    CGPoint stepVelocity = ccpMult(self.velocity, dt);
    
    self.desiredPosition = ccpAdd(self.position, stepVelocity);
}

Let’s break this down section-by-section:

When the force is removed, you want the player to come to a stop, but not immediately. Here you apply a 0.90 damping; in other words, reducing the overall horizontal force by two percent each frame.

These damping and clamping values put limits on how quickly things happen in the game. It also prevents the buildup of velocity problem that you experienced in the first part of the tutorial.

You want the player to have a maximum speed and to reach that speed within a second or less. This way your player's movements still feel natural, and provide a level of control. The maximum force that you'll allow is a positive 120 value, which would be one quarter the screen width per second.

If you want to increase the rate of acceleration of your player, increase the forwardMove variable and the damping value 0.90 respectively. If you want to increase your player’s maximum speed, simply increase the 120 value. You're also capping the jumping velocity at 250 and falling velocity at 450.

  1. You add a forwardMove force that will come into play while the user is touching the screen. As a reminder, you are scaling that force (800 points per second) to the appropriate amount for the current frame's timestep (dt) in order to have consistent acceleration.
  2. Here you apply a damping force to the horizontal velocity to simulate friction. You're applying physics here just as you did with gravity. In each frame, additional movement force will be applied.
  3. In section three, you check for the boolean (meaning that the screen is being touched) and add the forwardMove force if appropriate.
  4. In section four, you apply the clamping. This limits the player's maximum movement speed in both the horizontal (running top speed), upward (jumping speed) and downward (falling) directions.

Build and run. You should be able to make Koalio run forward by pressing the left half of the screen. Watch that Koala go!

Next, you'll make him jump!

Jake Gundersen

Contributors

Jake Gundersen

Author

Over 300 content creators. Join our team.