Hello and welcome to the second iteration of my FlashPunk Tutorial! If you haven’t read the previous tutorial, I suggest you do so, because this code is going to build up on it. You can just download the FlashDevelop project with the entire code here. The finished code for this tutorial is available here. This time I’ll show how to load OGMO oel files into your code and create Tilemaps out of them.
First of course, if you don’t know how to use OGMO, please go to the OGMO homepage and check out their tutorial.
Done? Got your 4 cups of coffee ready?
Okay, so….our goal this time is to load and read OGMO oels so that we can create Tilemaps.
As always, the following techniques aren’t necessarily the “right” ones. It’s just what worked for me. I also don’t claim to have come up with all of them by myself. Loading OGMO oels for example, I learned by going through ChevyRay’s
As you know after working through the OGMO tutorial, you first have to create an OGMO settings xml with the extension “.oep”. The settings define how the resulting oel is structured, which is very important to keep in mind, because this is the file you’ll later be parsing. So any mistake in the settings can result in errors in the parsing process later on (and you won’t get any syntax errors shown in the IDE)!
Here is the settings file we’ll be using this time. Put it into a new folder called “maps” inside the “assets” folder of your flash project.
As you can see, we define the dimensions to be 1248×768. These are clean multiples of 48, which is the uniform size for tiles and grid rects. For actual tile images, you can use this tileset here. Put it into your “gfx” folder inside your “assets” folder and call it “tiles.png”.
The working directory is the relative path from the settings file to the folder where we put our tileset. In the <tilesets> tag we simple give the name of the tileset file and set the dimensions of a single tile. The order in which the layers are defined in the <layers> tag is important, because layers that were before others appear to be behind them in the game.
The grid layer is used to define the collision areas. The tile layers are used to place the single tile images.
Let’s just make a very basic map using these settings. In OGMO, we first just fill the entire map with a simple grass tile.
Select the “ground” layer for this. Then select the “trees” layer and place the 2 halves of a tree, anywhere you like.
Mine looks like this:
Next, let’s place a house. Select the house layer and place a house anywhere you like.
Mine looks like this:
Okay. Graphically, our simple map is done. Now we need to set the collision areas. Select the grid layer, and place a black rect at the 2 tiles that the player musn’t be able to walk over in the game. I mean the house, and the lower part of the tree.
Mine looks like this:
If you look closely, you can see the tile images half transparent. Save the map as outdoors_map_01.oel inside the “map” folder. Now to some code!
We first want to create the Entity classes that we’ll need when loading the map in the Game.as class.
Let’s start with a class called Ground.as, which we’ll put into the “entities” folder.
Ground.as is extending Entity and basically has 2 tasks:
1. Read the ground layer data from the oel and use it to fill the tilemap property
2. Read the grid layer data from the oel and use it to fill the mask property
First off, we define the dimensions of tiles and grid rects separately. It is possible to have a grid that consists of rects that are smaller than the tiles, so we can have more accurate collision detection, but for simplicity’s sake,
I’m not going to do that here. So we just set width and height for both each to 48 pixels.
Next, we embed the tile set image “tiles.png” into the class, storing it in the TILE_SET constant. That shoudn’t be new to you at this point. We declare 2 variables “tilemap” and “grid”. They each hold the ground layer and grid layer data, respectively.
In the constructor method, we define the paramter “map” of type XML. This is the map information converted into an XML instance. It is the variable that must be parsed now. But before that, we name the type of the Entity to “solid”, meaning that any grid rect of the Ground class can be checked on for collision by using the label “solid”.
This will become clearer later on.
After that, we start getting into the real meat of the constructor. We set the graphic property of the Entity super class to our just recently declared tilemap object and at the same time instanciating it.
The Tilemap constructor method has these parameters:
1. The Class of the embedded tile set
2. The total width of the tilemap
3. The total height of the tilemap
4. The width of a single tile
5. The height of a single tile
As you can see, the total width and height are obtained from the map parameter. Calling the width and height properties actually looks up the <width> and <height> tags in the oel file that map refers to. Then we do a loop through all the <tile> tags inside the first <ground> tag (there is only one). For each <tile>, we read the data and set a new tile of the tilemap.
The parameters of the setTile() function are:
1. The column in the tilemap (A Tilemap is basically a 2 dimensional array)
2. The row in the tilemap
3. The index of the new tile in the tile set (meaning figuring out which tile sprite from the tile set to put at the column and row of the tilemap)
The column is figured out by dividing the x coordinate of the tile by the general tile width, and the row by dividing the y coordinate of the tile by the general tile height. Which makes sense. For example, if tiles are 48 pixels wide, then a tile at x=144 must be in the (144 / 48 = 3) 3rd column. The index can be gotten by calling the getIndex() method of Tilemap. The parameters are:
1. The column in the tile set
2. The row in the tile set
We can get the pixel coordinate of the tile image (the grass tile) by checking the tx and ty attributes. Each must be divided by the tile sprite width and height (48 pixels). The logic is practically the same as with first 2 paramters of the setTile() function. The 2nd and last major part of the constructor is getting the grid data and filling the grid and mask properties. Here is the initialization of the mask and grid:
It’s very similar to the initialization of the tilemap. Only bigger difference is that we don’t need to include a tile set, since the grid is about creating collision rectangles (the black boxes we placed in OGMO). After that we loop through all the <rect> tags within the first <solid> tag (there’s only one). Each time we call the grid’s setRect() method, which is far simpler than the setTile() method of the tilemap. Keep in mind that the grid is, much like tilemap, basically a 2 dimensional array of rects.
The parameters are:
1. The column of the rect in the grid
2. The row of the rect in the grid
3. The width of the rect
4. The height of the rect
We calculate the column and row by dividing the pixel coordinate of x and y respectively by the RECT_WIDTH and RECT_HEIGHT, also respectively. Same logic as before. The width and height of rect are just given straightforward.
Darn, this was a long ass explanation of the Ground class, but I feel it’s important to get the idea.
So…next class we write is another Entity class called Trees.
Create the class named “Trees.as” inside the “entities” folder.
Here it is:
Take a good look at it. Deja vu? It’s pretty much the same logic as in Ground.as, but instead of looping through
the <ground> tag, we’re looping through the <trees> tag. Another major difference is that we’re not setting up a grid this time. The collision rects for trees were included in the grid of Ground. Again, it might not be consequently logic-wise, but I wanted to keep things simple. I don’t think there’s much need for explanation with the Trees class.
The next Entity is House. I think you’re realizing by now that for each layer in the OGMO map, I’ve created an Entity.
The House class is a bit different though. Create a class called House.as in the “entities” folder.
Here goes House.as:
We set the dimensions of a house, and then embed the graphic into the class, storing it in the HOUSE constant.
The index property has a special purpose that isn’t very clear yet. Just know that it needs to be there for the features
we’ll implement later on. Right now, you just need to know that in the Game world, we’ll create an array of houses
and the index property stores the house’s index within this array.
In the constructor method, the house’s type is set as “house”, for later collision detection. Then we initialize the position and index of the house by obtaining the parameters of the constructor. And last but not least, we set the Entity’s graphic property to the HOUSE sprite, by creating a new Image. For collision detection, we also set the Entity’s hitbox. You could make the hitbox a smaller area than the overall sprite, in order to make collision detection a bit more accurate if the house had a weird shape. But we’re not doing that here, our house image is pretty rectangular.
Okaaaay, now we got our entities ready, now we just need to embed the OGMO map, convert the byte array into an xml and instantiate those entities in the correct order.
Open Game.as inside your “worlds” folder.
Change it to be like this:
As you can see, we’re finally embedding the map “outdoors_map_01.oel”, storing it in the constant Class OUTDOORS_MAP_01.
After that, we have an instance for the ground, trees and player each and an array for houses. Even though we currently only have one house, it’s useful to prepare for more potential houses.
In the constructor, you might notice that the add() call to add the player to the stage is gone, and instead we are calling
a function called loadMap(). The loadMap() function does all the instantiating of the entities and adding them in order.
If we had added the player before the loadMap() class, you wouldn’t have been able to see your avatar, buried underneath all those other layers.
The load map function needs explanation.
First we create helper variables for the loops we’re going to do. Then we convert the byte array of OUTDOORS_MAP_01 into a parsable XML, which we store in a variable called “xml” of type…XML!
This object is now fed to the constructor for our ground object, and then we add ground to the stage. Simple or what?
Then we add the player to the stage (the player was instantiated in the constructor already), and we do the same procedure with the trees as we did with the ground. In the end, we do some more xml parsing by looping through the <tile> tags of the <houses> tag in the xml (oel), but only if there is a <houses> tag at all!
We increment the “i” integer after each time a house was instantiated, pushed into the houses array and added to the stage. The house constructor doesn’t need to know more than the pixel coordinate of the house within the map, and the index within the houses array.
At this point you could try and run the program, but might be surprised that all the collision detection stuff we did seems for naught!
We need to fix something up in the Player class, to actually take collisions into account when moving.
So please open your Player.as class. We need to create one new function and update the if-else statements in the update() function. The new function is:
This function calls the collide() method of the Entity super class for each collision type. Remember how we defined the types “solid” and “house” in the Ground and House class before? Here is where we can check if our player is colliding with any entity of that type. The function in human-speak basically means: “If this entity would have been in this position (x, y), then would a collision occur with another entity of this type?”. If that’s the case with any of the types, we return true, if neither, then we return false.
To make use of this function, we change the if-else statements in the update() function like so:
Now, before every time the x or y coordinate is changed, we first check if the player would overlap with another entity that we don’t want it to overlap with at that position. If that’s not the case, go ahead and update the coordinate.
We’re almost done here, one thing needs to be added.
In the constructor function of Player, add one function call at the end.
This sets the hitbox of the player, to define the collision box/area of the player himself.
Okay, run the demo…it should work if you followed the instructions. If you find bugs or have suggestions on how to improve, please give me the feedback. If you’re too lazy to type it all out, you can still get the complete code here.
Next time we implement camera scrolling and multiple maps that we can transition to, as well as finally walk into those houses we put!