The Tile Engine: The Ins and Outs
squaring it all
Click to Start, Use Arrow keys to move, Space bar to shoot
Tiled games are just about the most common sort of games around. Well, no, I should rephrase that: Two dimensional Arcade games benefit with the use of a tile engine in such a way that you'd be hardpressed to find a well developed 2D arcade game that does not use some sort of tile logic. And I should stress the words "some sort." In the past few years the term Grid Collision has been kicked around, probably as an attempt to separate the terrain building part of the tile engine from the collision managing part. But it is true you don't have to use a tile engine for both purposes at the same time.
With a tile engine you divide the game screen in rows and columns, creating a grid of a fixed size. Because it has a fixed size, you can very quickly determine within which cell a point lies (a cell is created through the crossing of rows and columns.) And based on where this point will be next, you can also quickly determine if that movement is possible or not.
Picture a man walking towards a wall. The wall is at 200 feet from the man, he moves at about 5 feet per second (or per iteration of the system.) Instead of checking his distance towards the wall each time to determine if the man has reached it, you only check the next 5 feet. If within the next five feet the man has reached the wall, he stops, he can go no further. The system begins to show its merits when you add multiple walls, of various sizes, and spread them all over the place as in a maze, and you allow the man to move in any direction at any given time. With the grid logic in place, you don't have to loop through all the walls and check for collision, but continue to check on that tiny little 5 foot square. So loops are shorter, and the number of checks are reduced.
Types of Tile Engines
As with anything in programming, there are many ways to accomplish the same thing. And so there are many ways to build a tile engine. I will try to cover the most common ones and list their advantages and disadvantages. Many more types could be derived from these, by a simple matter of combination and permutation.
The Basic Tile Engine:
- In this system, which one could also call the simple tile engine, cells have the same size as the moving sprites. And they are perfect squares.
- All cells are completely filled or completely empty. So you don't have cells which are only half solid.
- Movement is limited to four directions, up, down, right, left.
- And the main characteristic of the basic tile engine: All movement is cell based. Meaning, sprites move as if they were pieces in a checkers game. They can't move in fractions of a cell. They leave one cell to occupy one next to it.
The advantage is of course that this is an incredibly easy engine to code. And you'd be amazed how many games use it.
The main disadvantages are: movement can seem rather dull and unappealing. There is no possibilty for friction, easing, springing, acceleration... And having cells of the same size as the moving sprites and having them either completely filled or completely clear, may reduce the "richeness" of the terrain. You may end up with a very blocky look.
The Slightly Complicated Engine:
Here you have the basic engine plus some sort of minor variation. Either the terrain tiles are no longer the same size as the moving sprites, or you allow for movement to be fractioned (and so allow for acceleration, easing, springing...). But still the cells must be completely filled or completely empty. Richer designs can be accomplished, however, through the use of smaller cells since the hero sprite does not have to be of the same size as the world tiles, and movement can be far more fluid and interesting.
The main disadvantage is that fractioned movement and richer designs always end up with more cells being checked for collision in each iteration. You will understand this a little better when I go over the code.
The Complicated Engine:
In this engine you have it all. The cells are rectangles, the sprites are of various different sizes, movement is fractioned, the cells may not be entirely filled, and the sprites can move diagonally.
The advantages are the same as the previous type, plus the ability to have even more complex terrains. However, optmization of code can be a bitch. One common mistake here is to use hitTest logic to determine collision with the oddly constructed, partially filled cells. Or even use the, admitedly much better, pixel perfect hitTest from the BitmapData class, but also flawed.
The problems you will encounter with the two last types of engine are basically the same. They will be either caused by the speed of the moving sprites, or the shape of the elements.
I have talked in previous tutorials of how bad it is to base collision on hitTest logic, because it is far better and far more advisable to only use geometric shapes in your collision logic and not worry about the bitmaps or vectors that skin these shapes. Code as if nothing is there on stage, only points, lines, circles, rectangles and triangles held in memory as simple numbers. Don't code as if you had a PNG, a rocket ship or solid ground... In fact, try never to do that.
One purpose of this Tile tutorial is to introduce the Isometric engine later on and by then it should become obvious why you should never use hitTest logic. And when I get to the line collision tutorials, you will see you may not need the pixel perfect collision logic of bitmaps after all.
The Problem With Speed
It is our old friend, the "I am not touching it now, and in the next iteration I will be so far beyond it, I will not be touching it then." I call it the ghost problem. It allows sprites to move through solid walls, bullets to move through sprites as if they are made of butter.
With tiles, this is a huuuuuge problem. Take an engine that looks perfect, but that uses some sort of hitTest logic for collision and then increase the speed of the moving sprite. Eventually, the system will break. I guaratee it. The sprite will go past a wall, or even weirder, it will stop before touching the wall, and will require an extra key press to touch it.
This is however easily fixed with the non-hitTest logic. You do however increase the number of cells checked against collision. But this process can be further optimized as I'll show you.
The Problem With Shape
This is a more complex problem and requires even more checks. Imagine your sprite is not a rectangle but a triangle, or an X. Collision detection then could be hell. The solution is to use body segmentation, meaning the sprite is divided into multiple shapes, and so when a sprite moves, it is as if more than one body is moving at the same time, and so collision logic is run on all the different segments.
Collision could be a simple matter of stopping movement as soon as any part of the body collides with a wall, or as complex as using inverse kinematics to reposition the various different parts once collision is first detected in at least one of them. It would depend on the game. But on the plus side, games that require this sort of logic may profit from a physics engine more than from a tile engine. Tile engines are good, but there are no panaceas in programming, there never was one, there never will be. So shop around.