Cocos2D-X Tile Map Tutorial: Part 2
Part 2 of a Cocos2D-X tile map tutorial series about his ninja and his quest for watermelon. By Jorge Jordán.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Cocos2D-X Tile Map Tutorial: Part 2
15 mins
Modifying the Tiled Map Dynamically
So far your ninja is having a fine time exploring, but this world is a little dull. There’s simply nothing to do!
Plus your ninja looks a bit hungry. So let’s spice things up by giving your ninja something to eat.
For this to work, you’re going to have to create a foreground layer for any objects you want the user to collect. That way, you can simply delete the tile from the foreground layer when the ninja picks it up, and the background will show through.
So open up Tiled, go to Layer\Add Tile Layer and name the layer Foreground. Make sure the Foreground layer is selected, and add a couple collectibles to your map. I liked to use the tile that looks like a watermelon or something to me.

Now, you need to mark those tiles as collectible, similarly to how you marked some of the tiles as collidable. Select the Meta layer, switch over to the meta_tiles view and paint a green tile over each of your collectables. You’ll have to click Layer\Raise Layer to make sure the Meta layer is on top so that the green is visible.

Next, you need to add the property to the tile to mark it as collectable. Right click on the green tile in the Tilesets section, click Tile Properties… and add a new property with name Collectable, value True and click OK.
Save the map and go back to Xcode. Add a new private property to HelloWorldScene.h:
CCTMXLayer *_foreground;
Then open HelloWorldScene.cpp, and add this line to the init method, right after loading background:
_foreground = _tileMap->layerNamed("Foreground");
This gets a reference to the foreground layer, which you’ll need later.
Next add these lines to setPlayerPosition, right after the if clause with the return in it:
CCString *collectible = new CCString();
*collectible = *properties->valueForKey("Collectable");
if (collectible && (collectible->compare("True") == 0)) {
_meta->removeTileAt(tileCoord);
_foreground->removeTileAt(tileCoord);
}
Here is standard stuff to keep a reference to the Foreground layer. The new thing is you check to see if the tile the player is moving to has the Collectable property. If it does, you use the removeTileAt method to remove the tile from both the Meta layer and the Foreground layer.
Build and run the project, and now your ninja will be able to dine on tasty-melon-thingie!
Creating a Score Counter
Your ninja is happy and fed, but as player you’d like to know how many melons he’s eaten. You know, you don’t want him getting fat on you.
Usually you’d just add a label to your layer and be done with it. But wait a minute – you’re moving the entire layer all the time, that will screw you up, oh noes!
This is a good opportunity to show how to use multiple layers in a scene – this is the type of situation they are built for. You’ll keep your HelloWorld layer as you’ve been doing, but you’ll make an additional layer called HudLayer to display your label. (Hud means heads up display).
Of course, your two layers need some method of communicating – the HudLayer layer will want to know when the ninja snacks on a melon. There are many ways of getting the two layers to communicate, but you’ll go with the most simple way possible – you’ll hand the HelloWorld layer a pointer to the HudLayer layer, and it can call a method to notify it when the ninja snacks.
So in Xcode click on File\New\File… and choose the C++ Class template under iOS\C and C++.
Click Next, name it HudLayer and click Create.
Open up HudLayer.h, and replace the contents with the following:
#ifndef __HUDLAYER_H__
#define __HUDLAYER_H__
#include "cocos2d.h"
using namespace cocos2d;
class HudLayer : public cocos2d::CCLayer
{
private:
CCLabelTTF *_label;
public:
// Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer)
virtual bool init();
// there's no 'id' in cpp, so we recommend to return the class instance pointer
static CCScene* scene();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// preprocessor macro for "static create()" constructor ( node() deprecated )
CREATE_FUNC(HudLayer);
void numCollectedChanged (int numCollected);
};
#endif // __HUDLAYER_H__
This creates a class that derives from CCLayer
, the Cocos2D-X class that represent a layer. It creates a private instance variable to keep track of the label to display, and has a helper function to update the number to display in the label.
Next replace HudLayer.cpp with:
#include "HudLayer.h"
using namespace cocos2d;
bool HudLayer::init()
{
if (CCLayer::init()) {
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
_label = new CCLabelTTF();
_label->initWithString("0", "Verdana-Bold", 18.0);
_label->setColor(ccc3(0,0,0));
int margin = 10;
_label->setPosition(ccp(winSize.width - (_label->getContentSize().width/2) - margin, _label->getContentSize().height/2 + margin));
this->addChild(_label);
}
return true;
}
void HudLayer::numCollectedChanged(int numCollected)
{
CCString *labelCollected = new CCString();
labelCollected->initWithFormat("%d",numCollected);
_label->setString(labelCollected->getCString());
}
In init
, you create a label and add it as a child of the layer. In numCollectedChanged
, you update the text of the label.
Now let’s put this layer to use. In HelloWorldScene.h, import your new file at the top:
#include "HudLayer.h"
And declare two new private properties – for your new layer, and the amount of watermelons collected:
HudLayer *_hud;
int _numCollected;
In HelloWorldScene.cpp, add this code to the CCScene * scene() method right before the return:
HudLayer *hud = new HudLayer();
hud->init();
scene->addChild(hud);
layer->_hud = hud;
This creates your layer and adds it to the scene. It also sets the hud variable on your main layer to the newly created layer, so you have a way to talk to it.
Finally, add this code to setPlayerPosition
, in the case where a tile is collectable:
_numCollected++;
_hud->numCollectedChanged(_numCollected);
Here you’ve modified the HelloWorldScene to call a method on the HudLayer when the count changes, so it can update the label accordingly.
Build and run the project, and if all goes well you should see a melon counter in the bottom right!
Gratuituous Sound Effects and Music
You know this wouldn’t be a game tutorial from this site without completely unnecessary but fun sound effects and music :]
Simply make the following changes to HelloWorldScene.cpp:
// At top of file
#include "SimpleAudioEngine.h"
// At top of init method
CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("pickup.caf");
CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("hit.caf");
CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("move.caf");
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("TileMap.caf");
// Inside setPlayerPosition, in case of collidable tile
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("hit.caf");
// Inside setPlayerPosition, in case of collectable tile
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("pickup.caf");
// Inside setPlayerPosition, right before setting player position
CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("move.caf");
Now your ninja can groove happy as he eats!