Cocos2D Tutorial for iOS: How To Create A Mole Whacking Game: Part 1/2

A Cocos2D tutorial on how to create a fun mole whacking game, that is a universal app for the iPhone and iPad. By Ray Wenderlich.

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.

Setting the Background

Next, open up HelloWorldScene.m and find your init method. Remove the four lines of code that create the Hello World label, and replace those lines with the following:

// Determine names of sprite sheets and plists to load
NSString *bgSheet = @"background.pvr.ccz";
NSString *bgPlist = @"background.plist";
NSString *fgSheet = @"foreground.pvr.ccz";
NSString *fgPlist = @"foreground.plist";
NSString *sSheet = @"sprites.pvr.ccz";
NSString *sPlist = @"sprites.plist";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    bgSheet = @"background-hd.pvr.ccz";
    bgPlist = @"background-hd.plist";
    fgSheet = @"foreground-hd.pvr.ccz";
    fgPlist = @"foreground-hd.plist";
    sSheet = @"sprites-hd.pvr.ccz";
    sPlist = @"sprites-hd.plist";            
}

// Load background and foreground
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:bgPlist];       
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:fgPlist];

// Add background
CGSize winSize = [CCDirector sharedDirector].winSize;
CCSprite *dirt = [CCSprite spriteWithSpriteFrameName:@"bg_dirt.png"];
dirt.scale = 2.0;
dirt.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:dirt z:-2]; 

// Add foreground
CCSprite *lower = [CCSprite spriteWithSpriteFrameName:@"grass_lower.png"];
lower.anchorPoint = ccp(0.5, 1);
lower.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:lower z:1];

CCSprite *upper = [CCSprite spriteWithSpriteFrameName:@"grass_upper.png"];
upper.anchorPoint = ccp(0.5, 0);
upper.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:upper z:-1];

// Add more here later...

OK let’s go over this section by section, since there is a good amount of new material here.

  • Determine names of sprite sheets and plists to load. This section lists the names of the sprite sheets and plists generated by Texture Packer to be loaded. Note that on the iPhone, Cocos2D will automatically choose between the “-hd” versions and the normal versions based on whether the Retina display is enabled. However, the iPad won’t load the “-hd” version unless you tell it to, so we check if it’s an iPad and use the “-hd” versions if so.
  • Load background and foreground. The next step is to load the information about each sprite for the background and foreground into the sprite frame cache so that they can be used later. Note that these sprites won’t actually be added to a CCSpriteBachNode anywhere – since these images are just used once each it would be kind of pointless.
  • Add background. The background image is added as a child of the layer (with a z of -2 so it appears beneath everything else) next. It scales the image by 2 because we made it smaller on purpose to conserve space, and centers the image.
  • Add foreground. The foreground is added in two parts. As an easy way to place the image, it sets the anchor point to the middle/bottom for the top image, and the middle/top for the bottom image, and matches that anchor point up to the center of the screen. That way you don’t have to do any complicated math, and it shows up in the right place on all devices. Note that part of the background will be offscreen for iPhones, but that is OK for this background and barely even noticable. Also note that the images are added with different z values, so the lower image appears on top.

Compile and run the code, and you should now see the background and foreground on the screen! Give it a try on both the iPhone and iPad simulators to make sure that it appears OK on both devices.

Mole Background

If you try the code on the retina display and zoom in, however, you’ll notice that it’s still using the normal artwork:

HD vs Normal Images in Cocos2D

That’s because we still haven’t done step 1 from the “Retina Display and Cocos2D” section earlier: call enableRetinaDisplay on CCDirector to enable retina display support when your app starts up.

To do this, open up WhackAMoleAppDelegate.m, and inside applicationDidFinishLaunching uncomment the following three lines:

if( ! [director enableRetinaDisplay:YES] )
    CCLOG(@"Retina Display Not supported");

Compile and run your code, and now when you try it on the retina display you should see it automatically make use of the HD files, due to Cocos2D’s built in retina display support!

Placing the Moles

For this game, you’re going to add three moles to the scene – one for each hole. The moles will usually be “underground” beneath the lower part of the grass – but occasionally they will “pop up” so you can try to whack them.

First, let’s add the moles to the level underneath each of the holes. We’ll temporarily make them appear above all the other art so we can make sure they’re in the right spot, then we’ll put them underground once we’re happy with their position.

Open up HelloWorldScene.h and add an array to keep track of the moles in the level, as shown below:

// Inside @interface HelloWorld
NSMutableArray *moles;

By storing the moles in this array, it will make it easy to loop through each of the moles later on.

Next, add the code to place the moles at the end of your init method (where it says “Add more here later…”), as shown below:

// Load sprites
CCSpriteBatchNode *spriteNode = [CCSpriteBatchNode batchNodeWithFile:sSheet];
[self addChild:spriteNode z:999];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:sPlist];      

moles = [[NSMutableArray alloc] init];

CCSprite *mole1 = [CCSprite spriteWithSpriteFrameName:@"mole_1.png"];
mole1.position = [self convertPoint:ccp(85, 85)];
[spriteNode addChild:mole1];
[moles addObject:mole1];

CCSprite *mole2 = [CCSprite spriteWithSpriteFrameName:@"mole_1.png"];
mole2.position = [self convertPoint:ccp(240, 85)];
[spriteNode addChild:mole2];
[moles addObject:mole2];

CCSprite *mole3 = [CCSprite spriteWithSpriteFrameName:@"mole_1.png"];
mole3.position = [self convertPoint:ccp(395, 85)];
[spriteNode addChild:mole3];
[moles addObject:mole3];

This first creates a CCSpriteBatchNode for the sprites, so that drawing the three moles is done more efficiently, and adds it as a child of the layer. Note it’s setting the z value to 999 temporarily, so that the moles apepar on top so we can make sure they’re set up OK.

It then loads all of the sprite frames from the property list to the cache, so they can be pulled out later.

Then it goes through and creates a sprite for each mole, places them in the scene, and adds them to the list of moles. Note the coordinate for each mole is within the 480×320 “playable area” of the game (the size of the iPhone). For the iPad, these points will need to be converted, so it calls a helper function convertPoint which we’ll write next.

Add the following method right above the init method:

- (CGPoint)convertPoint:(CGPoint)point {    
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return ccp(32 + point.x*2, 64 + point.y*2);
    } else {
        return point;
    }    
}

This method converts a point in the “playable area” to the appropriate screen positionon the iPad. Remember that:

  • We’re using the HD graphics on the iPad, so all points are doubled.
  • We’re centering that 960×640 area in the 1024×968 iPad screen, so that leaves 32 pixel margins on the left and right, and 64 pixel margins on the top and bottom.

So this method simply does that math to give the right position on the iPad.

One more thing – before we forget, add the following lines to clean up the memory we allocated for the moles array in the dealloc method:

[moles release];
moles = nil;

Compile and run your code, and you should see the three moles happily in the scene at the correct spots! You should try the code on the iPhone, iPhone Retina, and iPad to make sure that they’re in the right spot on each device.

Moles placed in correct positions