Monday, February 24, 2014

Putting the world into Perspective

One of the first things I did before even typing a single bit of code for the engine was to do some research on isometric engines created before and how they went about it. This wasn't limited to just the GameMaker software either, I looked through many different sources from programming it all in C++ to Unity. It's always good to absorb as much info as possible, just because it might not be the software or language you are using, doesn't mean there might not be a hidden tidbit you can use ;). After going over some of the most common methods I knew I really wanted a simple way to do it, not just for myself but for anyone else wanting to use the engine and you can't really get much simpler then the premise of the game being a top down map that is drawn in an isometric perspective. Here I'll explain how, in a tutorial style I handle the actual isometric coordinates in the engine.

To do this we take the objects/tiles position on the map and translate it, so we grab it's 'x' and 'y' on the map and set new variables, we'll call isoX and isoY based on it's current position.

isoX = ((x-y));
isoY = ((x+y)/2);

This will translate the 'x' and 'y' into isometric coordinates, but we need to do a little more here then that. For everything to tile nicely we need to make sure that the 'x' and 'y' are aligned onto a grid, so when translated and drawn the tiles align correctly. What size should our grid be though? A good rule is that it needs to be a square grid, like 16x16 or 32x32 for example. Sizes like 32x16 will place our tiles all wonky, remember this isn't our isometric tiles size just our top down grid. For our example we'll use 64x32 as the isometric tiles dimensions.

 What we want to do is make the grid for the top down map the size of the height of our tiles or 32x32 in our case. Why would we do that though? When the engine starts layering the tiles we need them to match up. Isometric tiles are drawn offset from each other with each row or column being offset usually by half of the tile size, so that the edges of the diamond shapes match up. If you look at this example, I highlighted the edges of the tiles touching. If the tiles are not offset correctly the edges won't line up. You can also see how the tiles are placed in a zig zag pattern.

The CoinPurse engine builds the map one column at a time, meaning we do not place a tile then offset down and over, build another tile and repeat for the whole map. We place one column of tiles end to end, then offset our position and build another row. So for this we need our tiles to match up when placed so we make our grid height our tiles height.

What about width? Remember isometric shifts each column of tiles in one direction so that the diamond shape of the tiles interlock and match up. We said the grid needs to be square, so if our height is 32 then our width must be 32 as well. Which just " happens ;) " to be exactly half of our tiles actual width, which when the grid is offset it is done by 32 and the tiles line up. It's important to have your tiles be the correct size and your grid setup to account for this otherwise tiles will overlap and not line up at all. I will discuss in a later blog post how to deal with uncommon isometric tiles that are for example 64x16(a very shallow isometric angle) or 64x48 ( a very steep one).

I know your asking, "But my tiles are not flat, they have varying heights. What about that?". That is true but all those tiles "should" be based of a default tile that "IS" flat or in a correctly proportioned cube. For example our tiles are 64x32 but if it was a cube tile, it would actually be 64x64 in size. So what do we do? we know that we can take that cubed tile and actually make it flat again into a 64x32 (the bottom face of the cube) so what we need to do is make sure the tiles origin is offset so that its at that 64x32 mark. Look at the picture below, it has our tile as a flat tile, then cubed. We show the bottom face of the tile highlighted in red, I included a textured tile as well for visualizing that bottom face.

To set the new origin for the CoinPurse engine, this is as simple as counting up from the bottom 32 pixels and setting the origin there. We maintain our tiles origin to the left so it's 'x' is always equal to 0 but it's 'y' is either 0 or adjusted depending on the tiles height and where the "bottom face" of the tile would be. The CoinPurse Engine does this because and I will discuss later, probably next weeks blog post, our tiles depth is determined by it's y and x so the further up and to the left you are the "deeper" in the map the tiles should be. Keeping the tiles origin in this location makes most of the work later on way easier and keeps such a nice consistency to handling the depth.

After we keep all this in mind when our map is finally drawn, everything will be lined up perfectly and we'll have an isometric map! We use the same tricks for other game objects like "players" or "enemies" within the game, converting there position on the map and drawing them in isometric, all the while technically the player is playing a top down game that just appears isometric. This is a really simple concept to grasp, once you have everything being drawn into isometric it makes adding anything else to the game very easy, and that has been the goal for the engine from the beginning. Provide scripts people can plop down in the "Create" and "Draw" event of an object and everything else works, from movement to the game view.

That's how the core of the engine works :) and in next weeks blog post, I'll discuss how depth and the Z axis comes into play with all of this. Be sure to leave and questions/comments you may have for me or the engine and thanks for reading! Be sure to follow/subscribe/share!

No comments:

Post a Comment