Today’s post is the second part of last week post about using sprite sheets with cocos2d and Tiled. In the previous post we saw what is a sprite sheet, how to to create it from a collection of individual sprites using Texture Packer and how to code it using cocos2d for iPhone. Today I’m going to explain how I used sprite sheets as source libraries in Tiled to create and edit New Sokoban puzzles. In this previous post I partially covered this topic. However, today I’m going to enter in more detail into some technical issues.
As we saw in the first part of this article, sprite sheets are mainly used to drastically improve our games performance in terms of both memory and CPU usage. We basically need to group our original individual sprites and then have some way to refer to them in our game code.
However, in my case I have used sprite sheets in some different way. In fact, I don’t refer to my sprite sheets directly in my New Sokoban‘s code as showed in the previous part of this article. What I have done is to use my sprite sheets as libraries for Tiled and integrated the resulting maps into cocos2d as Tile Maps.
Ok so, what is a tile map?
A tile map is the computer friendly representation of a map/level of our game using a tile arranged mapping. Imagine that our game world is divided into equally sized tiles that are the minimum significant unit of our game world. That’s to say, al graphics, physics and logics calculation need to be calculated per tile or group of tiles. We can’t calculated anything for under-tile magnitudes. Although it has obvious limitations, it also offers some very interesting benefits, as we will see later.
On the image above we have the typical tile map in Tiled. On the left we have the sprite sheet that serves as library of tiles to build tile maps. As you can see, when used as a tile map library, the sprite sheet is carefully crafted to be human friendly in order to facilitate the level design and creation process.
However, the concept of tile map needs something more to be completed: metadata. So, a tile map is represented with a sprite sheet and the metadata information that describe the map itself and how the meaningless tiles on the sprite sheet get relevant semantics in our game. For instance, in our game we probably will need to calculate collisions. The tile map needs to be able to represent collidable objects and our game code needs to correctly interpret them.
So, in the case of Tiled, the resulting file for a tile map is an XML as shown above. We will need to import both the library sprite sheet and this XML file to Xcode to be able to load our tile map into cocos2d.
Creating New Sokoban tiles
In fact, New Sokoban is not the typical tile map based game. Typical tile map based games are, for instance, old school “The Legend of Zelda” 2D games.
As you can guess from the above image, New Sokoban is not a typical tile map game. However, the squared nature of the game made me think about the option of using a tile map based engine to implement New Sokoban. Then I discovered that cocos2d includes a tile engine. I also discovered Tiled those days. So, easy implementation with cocos2d + no need to develop a custom puzzle editor for New Sokoban = give it a chance 🙂
So, first step was to create the tiles for New Sokoban. This is the most painful part. Mainly because it is better to create the tiles sprite sheet in a human friendly manner. It increases the amount of work in this initial phase but saves tones of time later, when designing, creating and editing puzzles.
Starting from a Photoshop image of the layout design of New Sokoban’s board, I started to manually create each of the tiles: select a 44×44 square in the layout PSD and copy it in another PSD file that acted as a temporal manually crafted sprite sheet. I know I said in the previous post that it is better to use Texture Packer to create the final sprite sheet, but I needed some way to visually arrange the sprites along the sprite sheet to assure that it was human friendly. And Texture Packer doesn’t include this feature at current version yet.
Next step is to create individual PNG files for each tile in the temporal sprite sheet. It would be a real pain to do it one by one… However, Photoshop has a very nice tool: “Slice”. With the Slice tool you can divide an image using the guides in it. So, I first situated the guides carefully (the blue lines) and then select “Slice/Slice from guides”.
Finally we need to select “File/Save for Web & Devices…”. This command will save our PSD sliced file as a collection of squared PNG files named sequentially. Absolutelly perfect as input for Texture Packer 🙂
Now, we only need to use Texture Packer to create our final sprite sheet as described in previous post and we are ready to move to Tiled.
Creating tile maps in tiled
Now that we have our library sprite sheet for Tiled we can use it to create puzzles for New Sokoban. To see Tiled in action refer to this previous post. Here I’m going to focus on metadata configuration for New Sokoban.
On the above image you can see my custom Tiled configuration to create puzzles for New Sokoban. I defined three Map Properties: name, 2stars and 3 stars. This properties store the name of the puzzle as it will be presented to the player on the game screen and the moves needed to get 2 and 3 stars.
Moreover, I have a specific layer configuration that allows me to get some semantics in code. We will see it in more detail later, but I have an internal engine structure that recognizes the layers in the above image and uses that information to calculate the logics needed to move the boxes, calculate collisions or know when a puzzle has been beaten.
So, when the puzzle is edited and the metadata is set, we are ready to load it into the game.
Tile engine in cocos2d
Cocos2d makes support for tile map based games very easy. Actually, it does all the hard work 🙂 After adding the sprite sheet PNG file and the Tiled TMX (XML) file to Xcode we can load the map using this piece of code:
CCTMXTiledMap *tileMap = [CCTMXTiledMap tiledMapWithTMXFile:@"puzzle_01.tmx"];
[self addChild:tileMap];
Then I obtain all the tiles in the different layers using the corresponding code. Below is the code to obtain the tiles in the “targets” layer:
// Process targets layer. CCTMXLayer *targetsLayer = [tileMap layerNamed:@"targets"]; s = [targetsLayer layerSize]; for( int x=0; x<s.width;x++) { for( int y=0; y< s.height; y++ ) { unsigned int tileGid = [targetsLayer tileGIDAt:ccp(x,y)]; if (tileGid) { // Create a new TileTarget object and add to arrays. TileTarget *target = [[TileTarget alloc] initWithSprite:[targetsLayer tileAt:ccp(x,y)] board:self]; [self setTile:target at:ccp(x,y)]; [targets addObject:target]; [target release]; } } }
I have some model classes that model my game world: Board, Tile, TileBox, TileWall, TileTarget… Here I determine the type of the tile based on the layer it is located and build my internal representation of the game world. For example, tiles that are in the “walls” layer are marked as collidable tiles, tiles located in the “counters” (boxes) layer are marked as collidable and movable, etc. Then I use this information to calculate all the logics of the game.
Conclusion
Wow! Quite a large post! Hope you have found it interesting and not so boring :p As you can see, my use and implementation of a tile based engine is not the typical one. However, it works fine for New Sokoban and allowed me to save tons of time.
How did you get the properties that you entered in the Map Properties box? I know how to get them for tiles and objects, but not from Map Properties. Thanks
I figured it out just by guessing! I used propertyNamed:
NSMutableDictionary *exitLeft = [theMap propertyNamed:@”exitLeft”];
NSLog(@”exitLeft = %@”, exitLeft);
Hello awdio!
This is the code I use to access the properties of a map:
NSDictionary *propertiesPuzzle = [tileMap properties];
if (propertiesPuzzle) {
// Name
namePuzzle = [propertiesPuzzle valueForKey:@”name”];
}
Pingback: Using sprite sheets in Cocos2d and Tiled (part 2) | Indie Dev Stories « OmNomRobot