Tile Based Game Overview

When it comes to making games there are several standard ways to implement physics. Games like Braids and N+ use vector-based physics engines with complicated geometry, whereas games like the GameBoy Pokemon titles use far more simple tile-based approaches. There are, of course, a wide range of games that do something in-between.

The original Legend of Zelda had a tile-based map but allowed the player to move arbitrarily between tiles. This allowed for fine tuned control in combat while reaping the benefit of an easily maintained tile-based map format.


Original LOZ Screenshot

A tile based map is when the chambers or areas of the game are subdivided into a grid of tiled images, allowing many areas to be created from a limited subset of images. This greatly reduces the amount of custom art required for a project, reduces the disk space requirements for all of those images, and makes creating new areas relatively easy. The drawback is that you are more or less stuck with placing things on the grid, which gives a blocky look to your game.

Mystic Dave is a puzzle game, and one in which I do not want to implement combat. As such I have decided to break from the free-range nature of the original LOZ and restrict motion to the grid as well, GameBoy Pokemon style.

Old Mystic Dave Screenhot

Old Mystic Dave Screenhot

In this old screenshot you can see that Dave is misaligned with the grid. Back then the map was defined on a grid, but the character could move around freely. This caused a lot of headache when it came to implementing physics and properly handling collisions. I could do it, but was it worth it?

As stated, I have moved to where all entities are restricted to the grid, thus making movement and collision detection far easier. Consider the following:

MysticDaveGridMystic Dave is located in tile (1,1). He is facing East, towards position (2,1), which has a block in the way. If the player hits the right arrow key, all I need to do is check whether that tile to the right contains anything that would block Dave from entering. If the target tile is free, then Dave can be moved to the next tile.

In code, this is roughly implemented as follows:

int dx = 0, dy = 0;
if ( keysPressed[DOWN] ) { dy = 1; }
elseif ( keysPressed[UP] ) { dy = -1; }
elseif( keysPressed[RIGHT]) { dx = 1; }
elseif( keysPressed[LEFT]) { dx = -1; }

int desDir = DirFromDelta( dx, dy );
int curx = player->GetPos()->GetTileX();
int cury = player->GetPos()->GetTileY();
int tx = curx + dx;
int ty = cury + dy;

//check if target is free
if ( curChamber->CanTileBeEntered( tx, ty ) ) {
curChamber->RegisterTileEntityInTile( player, tx, ty );
player->MoveDir( desDir, curx, cury );

The code simply determines the tile we are trying to move to, checks whether the tile can be entered, and then moves the player over. Note that movement doesn't happen instantly. Moving the player over instantly would look terrible and play poorly.

MysticDaveGrid2Here we can see Dave moving from a tile to the one to his right. He is undergoing a walking animation while simultaneously translating to the right. It takes 24 ticks ( 24/60 sec) for Dave to complete his motion so that everything looks nice and smooth and game play progresses at a good pace.

However, this causes a new issue to arise. Isn't Dave in two tiles at once?

Well yes, during his motion Dave is in both tiles at once. In the code segment above Dave is registered in the destination tile, but note that this does not free him from the tile he starts off in. Thus, Dave is occupying both tiles, preventing other entities from walking into either while his motion is taking place. Once Dave's motion completes it will automatically free him from the tile he came from, allowing other entities to potentially move into it.

This system for registering and freeing tiles makes collision detection easy, as you never have two collideable objects occupying the same tile(s) in the grid space. This makes movement logic far easier and prevents a lot of the headaches that come with multiple things moving into the same space simultaneously.

Developed this week:

I implemented smooth transitions between chambers! Woot!

Also did a little bit of work under the hood, changing how TileEntity positions are represented. Instead of using a vector in pixel space, position is now represented by an object containing a vector with coordinates in tile space and a pixel-space vector used as a delta off of that. This makes it much easier to tell which tile you are in while preserving the ability to plot anywhere in tile space.