This article was originally written for Darren Hebden's RLNews
[Note: C++ Class Definitions Will Be Used Throughout]
Section 1 : The Question
One of the most important things in writing a computer game of
any sort is the way in which you represent the universe the game takes
place in. In a rogue-like, you will need to represent several things:
#1. The Dungeon
#2. The Slimy Things in The Dungeon
#3. The Pointy Things with which a player kills Slimy Things
#4. The Player that holds the Pointy Things
This Article will cover #1: The Dungeon.
Section 2 : The Dungeon
Alright, we need to find some way to represent the corridors and
rooms of The Dungeon itself. One of the easiest and most flexible methods
of doing this is to create a two-dimensional array of cells. Each cell will
be a wall, a floor, a door, a hideous spiked pit of death, or any number of
other things we might want to represent as one tile:
int Type; // 0-Wall 1-Floor 2-Water 3-Open Door 4-Closed Door...
unsigned int Flags; // see below...
Section 2b : Bit-Flags
One of the more important and space-saving methods of information tracking
is the use of bit-flags. As you know, a number in a computer is represented
in binary, which is a series of ones and zeros... For instance the number
14 might be represented as:
Now, say we need to keep track of a number of things about a tile... Is it
lit? Is it explored? Is is permenatly dark? Is it hairy?
We can use each individual bit in an integer to keep track of a true/false
answer for questions like these.
So, how do you single out an individual bit? Well, bitwise operators come to
save the day.
We can single out individual bits of a number by using the & (bitwise AND)
operator. Each bit represents a power of two... So the first bit is 1, the
second is 2 the third is 4 the fourth is 8 and so on... The & Operator
takes two integers and returns an integer that only has 1 bits where the two
origional integers BOTH had 1 bits... So to single out a bit, we take the
variable containing the flags (Flags, in this case), and & it with the number
represented by the bit we wish to read. If the returned number isn't zero,
the flag is set, if it is zero the flag is not set...
This is a bit confusing, I'm sure, so here's some examples:
Example 1: (We'll use 16-bit integers to save space)
Flags : 0101000010010100
We want This Bit-^
It's the fifth bit, so 2^4 = 16.
16 is 0000000000010000... so
Flags & 16 = ?
Which is greater than 0, so the flag is set...
Flags : 0101000010010100
We want This Bit--^
It's the fourth bit, so 2^3 = 8.
8 is 0000000000001000... so
Flags & 8 = ?
Which is 0, so the flag is not set...
Section 2c : Returning to The Dungeon...
So we have our basic Tile class defined. All we need to do now is create
an array of these tiles:
Now, apply your favorite dungeon-generation method to this array of tiles and
viola! You have a dungeon.
Section 3 : Positional Representation
Anything in your Dungeon is going to have a position within the
Dungeon. This position is simply defined as an x and y coordinate within
the 2D array of Tiles. If a player is at 16,19 we could look up the tile
he is in using the line : Map, If the player is at 31,53 we could
use Map... So we can generalize and say that if the player had
a position holding X and Y we could use the line : Map[Player.X][Player.Y];
We might also want to extend a position definition by giving it a facing...
8 1 2
\ | /
/ | \
6 5 4
int X,Y; // Our (X,Y) Coordinates
int Facing; // The direction this object is facing.
Everything in your dungeon should have a position. Each Monster,
each item that is lying on the ground, and the player. This will allow you
to keep track of each thing and their relations to one-another.
Brian Bucklew, 18
Current RL Project : Dungeon or "This game needs a new name"... :)
Projected Beta Release : Early 98