How To Build a Monkey Jump Game Using Cocos2d 2.X, PhysicsEditor & TexturePacker – Part 2

In part 2 of this Monkey Jump tutorial series, you will add the hero to the game, make him move and jump, and start adding some gameplay. By .

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

Contents

Hide contents

How To Build a Monkey Jump Game Using Cocos2d 2.X, PhysicsEditor & TexturePacker – Part 2

30 mins

Jump, Jump!

Now, let's make the monkey jump. For this, you need to make the game detect touch events anywhere on the GameLayer, because you want the monkey to jump at every touch.

Open GameLayer.mm and enable touch detection by adding the following line to the init selector:

    // enable touches
    self.isTouchEnabled = YES;

Also add the following selector at the end of the file (but before the @end marker). It forwards the touches to the monkey object via the jump method.

    -(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [monkey jump];    
    }

You might notice at this point that you don't have a jump method in the Monkey class. That's what You'll add next. Switch to Monkey.h and add the following method definition just before @end:

    -(void) jump;

Now open Monkey.mm and add the following code before the @end marker:

    -(void) jump
    {
        [self applyLinearImpulse:b2Vec2(0,[self mass]*JUMP_IMPULSE) 
              point:[self worldCenter]];   

        [[SimpleAudioEngine sharedEngine] playEffect:@"jump.caf" 
              pitch:gFloatRand(0.8,1.2)
              pan:(self.ccNode.position.x-240.0f) / 240.0f 
              gain:1.0 ];
    }

All the above code does is to apply an impulse to make the monkey jump and play the jump sound. You'll pan the sound as you did for the object sounds in Part One of this tutorial.

Compile and run. Tap the screen to make the monkey jump.

Outta Sight!

But this is far from perfect: if you tap the screen multiple times, the monkey goes through the roof! Worse still, the camera does not follow the monkey.

Let's fix the camera first. Start by adding the following code to the top of the update selector, above the existing code, in GameLayer.mm.

    // 0 - monkey's position
    float mY = [monkey physicsPosition].y * PTM_RATIO;

The above code copies the monkey's y-position into a new variable mY. Of course, you could also access the monkey's ccNode and take the y-coordinate from there. The end result will be the same as multiplying his physics position by the PTM_RATIO.

Now, add these lines to the end of the update selector after the closing curly brace after section #7.

    // 8 - Adjust camera
    const float monkeyHeight = 70.0f;
    const float screenHeight = 320.0f;
    float cY = mY - monkeyHeight - screenHeight/2.0f; 
    if(cY < 0)
    {
        cY = 0;
    }

Here, you calculate a good value for the camera's y-coordinate, one that will more or less center the monkey on the middle of the screen. Clamp the value so that it does not go below 0 so that the camera does not move below ground level.

Now let's implement parallax scrolling of the background so that the monkey's movement appears more natural. The effect is quite easy to accomplish: just multiply the background layer by a factor below 1.0 and set the position for the layers. This will make the background layer scroll slower. The further away a layer is from the camera, the smaller the factor must be.

Add this code below the last few lines added to update:

    // 9 - do some parallax scrolling
    [objectLayer setPosition:ccp(0,-cY)];

    // move floor background slower
    [floorBackground setPosition:ccp(0,-cY*0.8)]; 

    // move main background even slower
    [background setPosition:ccp(background.position.x,-cY*0.6)];      

If the game runs on iPhone 5, additional layers exist: The frames on the left and right side of the display. Keeping them static would really look strange. But if you scroll them too, some additional depth is added to the game.

The frames are in front of the other layers - closer to the player - this is why you have to animate them faster.

    // 10 - animate left and right border on iPhone 5 - just a bit faster
    if(leftFrame && rightFrame)
    {
        [leftFrame setPosition:ccp(leftFrame.position.x,-cY*1.2)];
        [rightFrame setPosition:ccp(rightFrame.position.x,-cY*1.2)];
    }

Feel free to adjust the values to your liking.

That's it – compile and run. Tap the screen multiple times to see the monkey rise. And beware of flying monkeys!!!!

And It All Piles Up!

If you play the game for a while, you'll notice that the items continue to drop from the same fixed height – sometimes way below the monkey's current position. In fact, after some time, items don't even drop because they've piled up beyond the spawning point.

Fix this by changing the following line in GameLayer.mm's update method:

    float yPos = 400;

Change the above line to this:

    float yPos = 400 + mY;

Items will now spawn 400pt above the monkey's head, wherever it may be.

Back to the monkey. You'll have noticed that the monkey can actually jump again and again while up in the air. This just won't do. you need to fix it so the monkey only jumps when he has contact with the floor.

Let's start by counting the number of contacts the monkey makes with the floor.

Add a new variable to Monkey.h:

    int numFloorContacts;     // number of floor contact points

Switch to Monkey.mm and add the following two new collision detection handlers to the end of the file (but above the @end marker):

-(void) beginContactWithFloor:(GB2Contact*)contact
{
    numFloorContacts++;
}

-(void) endContactWithFloor:(GB2Contact*)contact
{
    numFloorContacts--;
}

As the names imply, the first one detects the beginning of a contact/collision with the floor and the second the end of a collision. In the beginContactWithFloor selector, you increase the value of the floor contact variable, and then decrease it in the endContactWithFloor selector.

These selectors are going to get called by GBox2D every time a contact starts or ends between the monkey and the floor. (Remember: you created a separate class for the floor so that GBox2D now can call the appropriate selector with the class's name).

Now, if the monkey is standing on the floor, then the numFloorContacts value should be at least one. Use this to your advantages by wrapping the code in the jump method in Monkey.mm with an if condition to see if the monkey is actually standing on the floor before jumping:

    -(void) jump
    {
        if(numFloorContacts > 0)
        {
            [self applyLinearImpulse:b2Vec2(0,[self mass]*JUMP_IMPULSE) 
                               point:[self worldCenter]];   
                            
            ...
        }
    }

Compile and run. Everything seems fine. Well... except that when the monkey lands on an object, he loses the ability to jump. To fix this, we're going to consider any contact the monkey has with objects similar to a contact with the floor.

And it's very simple to implement. Simply add a couple more collision-handling routines to the end of Monkey.mm and count object contacts the same way you counted floor contacts:

    -(void) beginContactWithObject:(GB2Contact*)contact
    {
        // count object contacts as floor contacts 
        numFloorContacts++;        
    }

    -(void) endContactWithObject:(GB2Contact*)contact
    {
        // count object contacts as floor contacts 
        numFloorContacts--;        
    }

Compile and run. Isn't it much better now? And your game is already playable!