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.

Jorge Jordán
Jul 22 2013 · Intermediate · Article · 15 mins

Version

Other, Other, Other

Mmm, that was tasty!

Welcome back to our 2-part Cocos2D-X tile map tutorial series!

Here you’ll learn how to make a tile-based game with Cocos2D-X, the cross-platform C++ port of Cocos2D-iPhone.

Note: This tutorial is a port of a similar tutorial for Cocos2D-iPhone. If you are looking for the Cocos2D-iPhone version, you can check it out here.

In the first part of the tutorial, you learned how to create a map with Tiled, how to add the map to the game, how to scroll the map to follow the player and how to use object layers.

This part of the tutorial covers how to make collidable areas in the map, how to use tile properties, how to make collectable items and modify the map dynamically, and how to make sure your ninja doesn’t overeat.

So let’s pick up where you left off last time and make the map a bit more game-like!

Tiled Maps and Collisions

You may have noticed that currently the ninja can move right through walls and obstacles with no problem at all. He is a ninja, but even ninjas aren’t that good!

So you need to figure out a way to mark some tiles as “collidable” so you can prevent the player from moving into those positions. There are many possible solutions to this (including using object layers), but I’m going to show you a new technique that I think is effective and also a good learning exercise – using a meta layer and layer properties.

Let’s dive right in! Load up Tiled again, click Layer\Add Tile Layer and name the Layer Meta. This is the layer you will be putting a few fake tiles in to indicate “special tiles”.

So now you need to add the special tiles. Click Map\New Tileset…, browse to meta_tiles.png in your TileGame\Resources\TileGameResources folder, and click Open. Set the Margin and Spacing to 1 and click OK.

With the Layers window selected, click on meta_tiles in the Tilesets window. You will see two tiles: red and green.

￼
There is nothing at all special about these tiles – I just made a simple image with two red and green tiles with partial transparency. Henceforth, red means “collidable” and it will be used to paint the scene appropriately.

So make sure the Meta layer is selected, choose the Stamp Brush tool, choose the red tile, and paint over any object that you want the ninja to collide with. When you’re done it might look like the following:

Next, you need to set a property on the tile to flag it so you can recognize in code that this is the tile that is “collidable.” Right click on the red tile in the Tilesets section, and click Tile Properties…. Add a new property for Collidable set to True like the following:

￼
Click OK, save the map and return to Xcode. Add a new private property to HelloWorldScene.h:

CCTMXLayer *_meta;

This will be a reference to your new meta layer. Add add a new public method declaration:

CCPoint tileCoordForPosition(CCPoint position);

This will be a helper routine you’ll write to convert a position to a tile coordinate.

Next open HelloWorldScene.cpp and add these lines to the the init method, right after loading background:

_meta = _tileMap->layerNamed("Meta");
_meta->setVisible(false);

This gets a reference to the meta layer, and turns it to be invisible. You don’t want the player to see red cactii!

Ok let’s stop here a second. Here you declare a member/variable for the meta layer as usual, and load a reference from the tile map. Note that you mark the layer as invisible since you don’t want to see these objects, they are for annotating what is collidable only.

Next you add a new helper method that helps you convert x,y coordinates to “tile coordinates”. Each of the tiles has a coordinate, starting with (0,0) for the upper left and (49,49) for the bottom right (in your case).

The above screenshot is from an older (Java) version of Tiled, by the way. Showing the coordinates for tiles is a feature they’ve ported to newer (Qt) version yet.

Anyway, some of the functions you’re about to use require tile coordinates rather than x,y coordintes, so you need a way to convert the x,y coordinates into tile coordinates. This is exactly what the function tileCoordForPosition does!

Getting the x coordinate is easy – you just divide it by the width of a tile. To get the y coordinate, you have to flip things around because in Cocos2D-X (0,0) is at the bottom left, not the top left.

Here you convert the x,y coordinates for the player to tile coordinates. Then you use the tileGIDAt function in the meta layer to get the GID at the specified tile coordinate.

Huh, what’s a GID? GID stands for “globally unique identifier” (I think). But in this case I like to think of it as the id for the tile is used, which would be the red square if that’s where you’re trying to move.

You then use the GID to look up properties for that tile. It returns a dictionary of properties, so you look through to see if Collidable is set to true, and if it is you return immediately, hence not setting the player position and making the move invalid.

And that’s it! Build and run the project, and you should now no longer be able to walk through any tiles you painted red:

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!

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:

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++.

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.

If you have any additional tips or suggestions for how to effectively use Tiled or tile-based maps in Cocos2D-X effectively, or if you’ve used or are planning to use tile-based maps in your projects, please share below!