This page contains useful information on DGC, games programming and DirectX
I-III
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Tile-Based Games FAQ version 1.2
by Greg Taylor
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
File : tilefaq.12
Home site: x2ftp.oulu.fi : pub/msdos/programming/docs
Version : 1.2
Released : 4-20-95
Tilefaq 1.2 Copyright 1995 Greg Taylor. All rights reserved.
Appendix I Copyright 1995 Chris Palmer. All rights reserved.
This document is freely redistributable provided that is
distributed in its entirety, with this copyright notice included verbatim.
There are no restrictions on works derived from this document.
-------------------------
- I : Introduction... -
-------------------------
There has been a fair response to my initial release of this file and there have been many
requests for additional information, all of which I will cover in this version.
This FAQ emphasizes on the style of graphics similar to those used in U6 and U7 by Origin.
Many of the techniques presented are aimed at systems with limited memory and/or speed
like PCs with a 640K barrier; but this document also includes alternative methods and
suggestions on how to code for less restrictive systems. This is just a brief, but
hopefully complete overview of one method to achieving the
Tile-based style. There are other methods and I'd like to hear about them, because much of
this FAQ has been pieced together from various implementations of the 'Tile' graphics
style.
---------------------------------
- II : Multiple layered maps. -
---------------------------------
This is an essential section to master because of the possibilities that stem from having
more than one layer of map. Almost all of your traditional effects can be more easily
implemented with a multi-layer
map as compared to a single layered one.
One of the key considerations when doing a multi-layer map is the speed of your drawing
routines. Since you may be drawing each tile several times, the speed at which that
routine performs is vital to producing a fast game. These should be coded in Assembly if
possible or if in a higher level language, should be optimized as well as possible.
A 'SEE-THRU' tile placement routine is another important tool that is a major part of
Tile-games. I would separate my place-tile routine into two independent routines, one with
0 pixels 'SEE-THRU' and the other which doesn't. This allows you to place tiles that don't
have the need for the SEE-THRU option to be drawn faster.
-----------------------------------
- II i : SEE-THRU Tile routines -
-----------------------------------
For those who do not have a SEE-THRU routine written and are wondering how you write one,
here's a brief overview. Basically, when you are copying your tile over, copy only the
non-zero pixels to the screen (it doesn't -have- to be zero, it can be any of the palette
values, but zero has become a sort of standard). And when you draw your tiles, color the
areas which you would like to be seen thru, with the zero color. Thus allowing you to lay
one tile over another, without destroying all of the image beneath.
A SEE-THRU routine is slower due to the check for the zero value, so it should only be
used when necessary.
Another 'SEE-THRU' sort of technique I've seen used is what the programmer termed a
'SEE-FORTH' routine. In this one he checked the destination pixel and only put the pixel
color where there wasn't already a pixel there (ie the pixel location had a value of 0).
This routine is not as useful in tile games, but it is a possibility that I've seen used,
so I thought I'd mention it.
---------------------------------
- II ii : The Multiple Layers -
---------------------------------
I use a three-layer map and it works fairly well for all of the things I do in my tile
games. A fourth layer can provide even more effects and a two layer map is possible as
well, but I find three to be the optimum number.
I split the layers up as such...(these will be referenced to throughout the remainder of
this text)
Layer Name - The types of tiles used in each layer...
BASE : Grass, Dirt, Brick, Stone, Doors, Water...
FRINGE : Trees, Rocks, Tables...
OBJECT : Swords, Booty, People, Monsters, Keys...
A sample map variable declaration with three layers might be...(C code)
#define SIZE 128
typedef struct {
unsigned char base[SIZE][SIZE];
unsigned char frng[SIZE][SIZE];
unsigned char obj[SIZE][SIZE];
} maptype;
Or perhaps...(to address the layers numerically) (C code)
typedef unsigned char maptype[3][SIZE][SIZE];
These are drawn on the screen in the order as listed above. The BASE layer is drawn first,
without the use of your SEE-THRU routine (Since it's the base). Then you draw the FRINGE
over the BASE using your SEE-THRU routine.
The FRINGE layer is about the most useful tool in producing powerful graphics easily. A
FRINGE tile might be a tree, with zero-values every where around the tree. Then you could
place the tree on any of the BASE tiles. This allows you to have one tree drawing, but it
can be a 'tree-on-grass' or a 'tree-on-dirt' or even a strange 'tree-in-the-water'.
Other possible FRINGE tiles are transitions. These are like going >from grass-to-dirt
or dirt-to-stone. The FRINGE layer allows you to draw one set of transitions, for example
grass, and then use those
to do all of your grass-to-?? transitions. This is a nice use of the FRINGE layer to save
you from drawing endless tiles.
Tables and other non-pick-up-able objects are perfect for FRINGE, this way they can be
placed on any BASE tile you like. The possible uses of this layer of map are enormous.
After drawing both of the other layers, draw your OBJECT layer. This layer is where you
store things that move or can be picked up, etc. including monsters, keys, townspeople...
This makes it easy to pick
up and put down objects without destroying other parts of your map.
---------------------------------------------------------
- III : Walkability - restricting character movement. -
---------------------------------------------------------
I usually assign an attribute I call the 'walkability' to my BASE tiles. This provides a
fast, easy, way to check whether you can/cannot move to a certain space, and it also helps
you to control other special
occurrences with a relative level of ease.
At each position in my map arrays, I have a byte (unsigned char) value which serves as
both the tile-index and the walkability value. I use a set of 128 tiles, and split them up
as such...
0-127
0-63 : Normal, walkable tiles, dirt, grass etc.
64-127 : Normal, unwalkable tiles, walls, etc.
128-255
128-191 : Special tiles, group 1
192-255 : Special tiles, group 2
When I'm drawing the screen, I simply use the REM (or MOD) statement or equivalent to get
the proper value, by MODing the number by 128. This gives a value from 0-127, which is the
actual tile-index number. When it comes to checking if that tile is 'walkable', you then
would divide the number by 64, yielding a value of 0, 1, 2, or 3...
0 : Walking is OK
1 : Walking is not OK
2 : Special thing happens when they step here - group 1
3 : Special thing happens when they step here - group 2
The first two values are simply understood, but the special values might need some
explaining...This allows you to program in special occurrences that happen when that space
is walked on. When it hit's a special square for instance, you would check through the
special spots list for the x,y coords of the spot that triggered the special occurrence
and the level map that it is on. This allows an easy way to throw cool stuff into your
game with little work. Why it is split into two groups is so that you
need not search ALL of your specials for that particular map at once, searching for the
effects of that one.
You will note that the WA (Walkability) value of 3 represents the section of tiles which
are unwalkable normally (like walls etc.) These can make for excellent 'secret' walls and
so forth.
The walkability setting can also be stored as a separate element of your map structure, to
increase speed, at the expense of memory. Having it as a separate element allows you to
include many more than 4 settings to the rating, allowing for 'level exits' and so forth
without having to resort to listing them as 'specials'. The method I list above with the
byte being split into the various categories is the most general
compromise between, ease, speed, and memory, I have come up with; but on systems where
memory is not much of a constraint, having walkability stored in a seperate element of the
map structure is usually a better way to go. More mention is made to the 'Walkability'
values later in the text.