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

In this part of the series, you’ll make your game fully capable of handling collisions. In other words, by the end of this part you’ll be able to reward and kill the mouse! 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.

Implementing Collisions: Lasers

The next step is to handle the collision between the lasers and the mouse.

Add the following at the end of setupCollisionHandling in HelloWorldLayer.mm:

    [loader registerPreCollisionCallbackBetweenTagA:PLAYER
                                            andTagB:LASER
                                         idListener:self
                                        selListener:@selector(mouseLaserCollision:)];

The above code registers a pre-collision callback for collisions between the player and the lasers. Since the laser sprites are not sensors, you want to receive notifications about this type of collision on every frame in order to kill the mouse when the laser does become active.

Add the mouseLaserCollision: method:

-(void)mouseLaserCollision:(LHContactInfo*)contact {        
    LHSprite* laser = [contact spriteB];
    int frame  = [laser currentFrame];
    
    // If we make the laser a sensor, the callback will be called only once - at first collision.
    // This is not good as we want to kill the player when the laser changes to active.
    // So we disable the contact so that the player and laser don't collide, but trigger a collision.
    // Disabling the contact is only active for one frame,
    // so on the next frame the contact will be active again, triggering the collision.
  
    b2Contact* box2dContact = [contact contact];    
    box2dContact->SetEnabled(false);
    
    if(playerIsDead)
        return;
    if(frame != 0) {
        [self killPlayer];    
    }
}

The above code gets sprite B from the contact info. In this case sprite B is the laser. Then the code takes the current frame from the sprite, because it needs to test if the laser is active so that the player can be killed if it is.

Then the code takes the Box2D contact information from the LevelHelper contact object and disables the contact so that no collision behavior will occur during the current frame. It then checks whether the player is dead. If so, nothing further is done.

Finally, the code tests if the frame number is not 0. If it is 0, then the laser is not on and the player is safe. If it’s not 0, it means that the mouse struck a live laser and so, the player has to be killed.

The above code has two elements that have not been defined yet: the killPlayer method and the playerIsDead variable. So let’s define them.

Switch to HelloWorldLayer.h and add the following instance variable:

bool playerIsDead;

Then add the killPlayer implementation to HelloWorldLayer.mm:

-(void)killPlayer {
    playerVelocity = 0.0;
    playerShouldFly = false;
    playerIsDead = true;
    playerWasFlying = false;
    [rocketFlame setVisible:NO];
    [player prepareAnimationNamed:@"mouseDie" fromSHScene:@"Animations"];
    [player playAnimation];
    
    [paralaxNode setSpeed:0];
    
    CGSize winSize = [[CCDirector sharedDirector] winSize];
    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Game Over"
                                           fontName:@"Marker Felt"
                                           fontSize:64];
    label.color = ccRED;
    label.position = ccp(winSize.width*0.5, winSize.height*0.75);
    [self addChild:label];
    
    CCMenuItem *item = [CCMenuItemFont itemWithString:@"Restart"
                                               target:self
                                             selector:@selector(restartGame)];
    CCMenu *menu = [CCMenu menuWithItems:item, nil];
    [menu alignItemsVertically];
    
    [self addChild:menu];
}

This is what the above code does:

  • Set the velocity of the player to 0. If the player was flying, he will now fall to the ground.
  • Set the playerIsDead variable to TRUE so we know the player is dead in the methods where this information is a factor.
  • Hide the rocket flame.
  • Start the death animation on the player sprite by using a LevelHelper method that will take as arguments the animation’s unique name and the sprite on which the animation should be performed.
  • Stop the parallax from moving by setting its speed to 0.

Note: For more details on using animations with LevelHelper, check out the LevelHelper API via the Documentation tab in LevelHelper.

Now you need to create a Cocos2d menu so that you can restart the game if the player dies. Define the necessary method method as follows:

-(void)restartGame {
    [[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
}

Compile and run. Your mouse can now die if he collides with a laser!

Note: If a collision does not work as it should, check to make sure that you have the correct tags set on the sprites.

Mouse dies upon colliding with a laser

Gratuitous Sound Effects

If you’ve read game tutorials on this blog before, you know we’d never leave you hanging without some gratuitous (and awesome) sound effects! :]

Navigate to your Xcode Resources folder in Finder. Then, open a new Finder window and navigate to where you saved the sounds pack that you downloaded at the beginning of this tutorial.

Inside the Resources folder, create a new folder called Music, and drag all the sound files from the sound pack into this new folder.

Now go back to Xcode and add the music assets to the project by right-clicking (or Control-clicking) on the Resources folder and choosing “Add Files to RocketMouse.”

From the new dialog, navigate to your Resources folder, select the Music folder, and click the Add button.

Your new Resources folder in Xcode should look something like this:

Now that you’ve added the sound files to your project, let’s add some code to make some noise!

At the top of HelloWorldLayer.mm import the audio engine:

#import "SimpleAudioEngine.h"

Now add a new method that will load the sounds:

-(void) setupAudio {
    [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"backgroundMusic.m4a"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"coin.wav"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"fly.wav"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"ground.wav"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"hitObject.wav"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"laser.wav"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"lose.wav"];
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"bunnyHit.wav"];
}

Next, add the following line to init (right before the call to scheduleUpdate):

[self setupAudio];

This loads all the sounds in the pack – backgroundMusic.m4a is loaded as a music asset and the rest of the files are preloaded as effects. Now we have to match the sound effects to the events that will generate them.

Add the following to the end of mouseCoinCollision::

    
[[SimpleAudioEngine sharedEngine] playEffect:@"coin.wav"];

In mouseLaserCollision: add the following inside the if(frame != 0) block:

    
[[SimpleAudioEngine sharedEngine] playEffect:@"laser.wav"];

Let’s also add a flying sound. Inside update:, add the following inside the if (playerShouldFly) block:

    
[[SimpleAudioEngine sharedEngine] playEffect:@"fly.wav"];

Compile and run. Enjoy the new music and sound effects! :]

The complete project up to this point can be downloaded from here.

Collisions Between Mouse, Cats, and Dogs

At this point the mouse can die if he hits a laser, but he’s getting off too easy when it comes to the cats and dogs! So let’s add some collision handling for the cats and dogs.

Add the following to the end of setupCollsionHandling:

    
    [loader registerPreCollisionCallbackBetweenTagA:PLAYER
                                            andTagB:DOG
                                         idListener:self
                                        selListener:@selector(mouseDogCatCollision:)];
    [loader registerPreCollisionCallbackBetweenTagA:PLAYER
                                            andTagB:CAT
                                         idListener:self
                                        selListener:@selector(mouseDogCatCollision:)];

Your game will perform the same action for collisions with both cats and dogs. So you need only one method – implement it as follows:

    
-(void)mouseDogCatCollision:(LHContactInfo*)contact {
	[[SimpleAudioEngine sharedEngine] playEffect:@"hitObject.wav"];
    [loader cancelPreCollisionCallbackBetweenTagA:PLAYER andTagB:DOG];
    [loader cancelPreCollisionCallbackBetweenTagA:PLAYER andTagB:CAT];
    [self killPlayer];
}

The above plays the sound effect and cancels the collision callback between the player and the cat or dog, since we no longer need it. Then the player is killed.

Compile and run. Now your mouse can die if he hits a cat or dog too – so watch out! :]

Mouse dies from hitting a dog