How to Make a Game Like Jetpack Joyride using LevelHelper, SpriteHelper [Cocos2D 2.X edition] – Part 2

This is a post by special contributor Bogdan Vladu, an iOS application developer and aspiring game developer living in Bucharest, Romania. Welcome back to our Jetpack Joyride tutorial series! In this tutorial series, we are making a game similar to Jetpack Joyride using Cocos2D and Box2D, and the LevelHelper and SpriteHelper tools. So far, we’ve […] By .

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

Creating Tags to Perform Collisions

In order to identify collisions between your sprites, you need a way to register collisions between sprites of one type with sprites of another type.

You will achieve this by separating your sprites into types using tags – all dog sprites will have the tag “DOG” and all cat sprites will have the tag “CAT” and so on.

To create the tags, in LevelHelper select the “Custom Properties” tab.

In the Tag Management section, enter the name for the new tag and click the Add button to create it. Create the following tags: DOG, CAT, LASER, COIN, PLAYER.

Now that you have the tags defined, you need to assign the tags to sprites.

Switch back to the Level Editor tab and select all the dog sprites from the list of sprites on the left. Then under General Properties, assign the DOG tag to all of those sprites.

Repeat the process for the other sprites. Assign PLAYER to the mouse sprite, CAT to all the cat sprites, LASER to all the laser sprites, and COIN to all the coin sprites.

When you’re done, save the level with Command-S.

Since you added tags, you need to regenerate the supporting code in order for the tags to exist in the code. So go to File/Generate Code/Cocos2d With Box2d and re-generate the code, replacing the old version.

If you look in LevelHelperLoader.h now, you will see that the tags are there.

Note: Every time you change, delete, or add a custom property (tags or classes) you need to regenerate the code.

A project with the code up to this point can be downloaded from here.

Coding the Game Logic

You are now (finally) ready to start coding your game. So switch back to Xcode, open your project and get ready for some real fun :]

In order to control the movement of the parallax and allow the player to jump, you need to have a few variables that will point to the objects created by LevelHelper. Add these lines to HelloWorldLayer.h inside the class definition:

LHParallaxNode* paralaxNode;
LHSprite*   player;
LHSprite*   rocketFlame;

Then add the following method prototype right before the @end:

-(void) retrieveRequiredObjects;

Inside HelloWorldLayer.mm add the new method implementation:

-(void) retrieveRequiredObjects {
    //Retrieve pointers to parallax node and player sprite.
    paralaxNode = [loader parallaxNodeWithUniqueName:@"Parallax_1"];
    NSAssert(paralaxNode!=nil, @"Couldn't find the parallax!");
    
    player = [loader spriteWithUniqueName:@"player"];
    NSAssert(player!=nil, @"Couldn't find the player!");
        
    rocketFlame = [loader spriteWithUniqueName:@"flame"];
    NSAssert(rocketFlame!=nil, @"Couldn't find flame sprite!");
    
    [rocketFlame setVisible:NO];
}

The first line retrieves a pointer to the parallax node using the unique name assigned in LevelHelper.

Then a pointer to the player sprite is retrieved, also by giving the unique name. You might need to modify the unique name in LevelHelper to read “player” as shown in the screenshot below if it isn’t set to that already.

Similarly, you should change the unique name of the flame to “flame” so it matches the code.

When you use spriteWithUniqueName: to look up a sprite, you get a LHSprite* instance, which is a class derived from CCSprite.

Finally, the pointer to the flame sprite is used to make it invisible. You only need to see the flame when the player is flying. (You could also have done this inside LevelHelper by unchecking the Visible option in the General Properties section but then you wouldn’t be able to see the flame in the Level Editor and so it would be harder to set up the scene properly.)

Now that you have the method defined, let’s use it (after you’ve loaded the level) via init – add the following right before the [self scheduleUpdate]; line:

    [self retrieveRequiredObjects]; // Retrieve all objects after we’ve loaded the level.

Compile and run, and if the flame is invisible when the game starts, you know it’s working so far! :]

The flame is now invisible.

Making the Player Fly

Time to let the mouse fly!

Add the following instance variables to HelloWorldLayer.h:

float  playerVelocity;
bool   playerWasFlying;
bool   playerShouldFly;

Now inside HelloWorldLayer.mm, replace the existing touch functions with the following:

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    playerVelocity = 0.5f;
    playerShouldFly = true;
    [rocketFlame setVisible:YES];
    [player prepareAnimationNamed:@"mouseFly" fromSHScene:@"Animations"];
    [player playAnimation];
}

////////////////////////////////////////////////////////////////////////////////
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    
}
////////////////////////////////////////////////////////////////////////////////

-(void)cancelPlayerFly {
    playerShouldFly = false;
    [rocketFlame setVisible:NO];
    playerWasFlying = true;
    playerVelocity = 0.0f;
}

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self cancelPlayerFly];
}

-(void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self cancelPlayerFly];
}

In ccTouchesBegan:, when the user touches the screen, playerShouldFly variable is set to YES, the rocket flame becomes visible and the flying animation starts on the player sprite. The code also starts the animation named “mouseFly” on the player instance.

To start any animation on a sprite, you just prepare the animation on that sprite similar to this:

[player prepareAnimationNamed:@"mouseFly" fromSHScene:@"Animations"];

And then play that animation as follows:

[player playAnimation];

To prepare an animation you just need the animation name and the SpriteHelper document containing the animation.

When the player stops touching the screen, or the touch is canceled, you call cancelPlayerFly to stop the mouse flying. You also hide the flame because the player is no longer flying.

But this isn’t enough. You set up the flag to indicate that the the player is flying, but you haven’t implemented the actual flight. That requires adding the following code to the end of update::

    if (playerShouldFly) {
        [player body]->ApplyLinearImpulse(b2Vec2(0, playerVelocity),
                                          [player body]->GetWorldCenter());
        playerVelocity += 0.01f;
        if(playerVelocity > 1.5f)
            playerVelocity = 1.5f;
    }

Here, you check if the player should fly and if true you apply a linear impulse with a horizontal direction (on Y) on the mouse Box2D body. The mouse Box2D body is retrieved using the “body” method of the LHSprite class.

You then make the velocity bigger and bigger, so the player will look like they are taking off from the ground, gaining speed with time. If the player’s velocity reaches a certain speed (1.5), you stop the speed from increasing further.

Compile and run. The mouse can now fly when you touch the screen!

A flying rocket mouse!