The Allegro Wiki is migrating to github at https://github.com/liballeg/allegro_wiki/wiki
First of all we have to choose a game idea to make and then analyze it so we can create a design plan. This plan will sketch out how we will implement some of the game features.
I have chosen to do a version of an old Atari game called Dandy. Although the name may be unfamiliar, the genre should not be as it was actually the inspiration behind the Arcade game Gauntlet. Featuring up to 4 players, moving monsters, skull generators, keys, doors and exits, Dandy offers the basic gameplay which Gauntlet later developed.
The Gauntlet / Dandy genre is an excellent game style to use because it features some of the base features used in many 2D games such as multiplayer options, scrolling, multiple level designs, scoring, item collection and different level features.
Here is a screen shot of Dandy on the Atari 800XL computer:
(Obviously the 4 color blocky graphics appear primitive by today's standards. Rest assured we will aim to improve the graphics!)
There are some important differences between Dandy, made in 1983 and running on 8-bit technology, and Gauntlet which was made 2 years later and with the latest arcade technology. Here are the main differences:
- Dandy features scrolling levels which are smaller in size than Gauntlet.
- Dandy features more limited level features
- Dandy features no animated graphics.
- All movement in Dandy occurs in a series of tile based jumps in exactly the same way as the sprites moved in the Atari game Boulderdash. This is in contrast to the smooth motion of normal sprites, but does also give the gameplay a different feel, and has advantages as well as disadvantages over normal sprite movement.
The use of smaller levels and jumping sprites makes the gameplay faster, tighter and considerably more difficult when hundreds of monsters and skulls are visible in some levels.
For our game, which I am tentatively titling “Free Dungeons,” we will improve the graphics, increase the maximum map sizes, but keep the jumping non-animated sprite style for gameplay reasons.
Now that we have the game idea, we need to analyze the original game in greater detail to see what features we want to keep and which we want to remove or improve. It is important to note that we will not just be copying the original game: this will be a tribute to Dandy, while improving on some aspects.
Dandy runs in a 320 x 192 screen mode with the levels composed of arrangements of 16 x 16 pixel tiles. Due to the status panels present in the display the visible area of each level is 20 x 9.5 tiles. Each level is 60 x 30 tiles in size and so the player can see roughly a third of the width and a third of the height of the level at any one time.
Dandy features 16 different level tiles which are:
- Floor – Empty tile that can be moved into and shot through
- Wall – Solid tile that cannot be moved or shot through
- Lock – As in Gauntlet, locks are opened by collecting keys and then moving against the lock. One key will open all touching locks and up to 9 keys can be collected.
- Start – Start tiles control the start position for players.
- Exit – Exit tiles control the exits from levels (note there can be multiple exits).
- Key – Up to 9 keys can be collected and used to open locks.
- First Aid Pack – First Aid packs can be collected and used with a specific key press to restore full health at the cost of a pack. A maximum of 9 packs can be stored at any one time.
- Cash – Cash gives points and also blocks monsters movement.
- Smart Bomb – Smart Bombs can be collected and used with a specific key press to destroy all monsters and skulls visible on the screen. A maximum of 9 bombs can be stored at any one time.
- Monster 1 – Monsters come in 3 varieties, with 1 being the weakest and 3 the strongest. When hit, a monster will change into a weaker variety, so monster 3 would become monster 2, then monster 1 and then die when hit for the 3rd time. Consequently, the monster number also refers to the number of hits to kill each monster. This method will also be familiar to players of Gauntlet as it was also used for the game's monsters.
- Monster 2 – See Monster 1
- Monster 3 – See Monster 1
- Heart – Hearts act to allow dead players to re-enter the game. If the game is being played by more than one player, but at least one player had died then shooting a heart revealed a dead player brought back to life. However, if no players have died or it is a one player game then shooting the Heart reveals a Monster 3 instead.
- Skull 1 – Skulls 1 to 3 generate monsters as in Gauntlet and downgrade when hit by weapon fire in the same way as for the monsters. Skull 1 will generate a Monster 1, Skull 2 will generate a Monster 2, and Skull 3 will generate a Monster 3.
- Skull 2 – See Skull 1
- Skull 3 – See Skull 1
These 16 different tiles are all that are used to make up the 26 different levels playable in the original game. However, a lot of variety and different levels can be made with just these limited number of tile types.
Both skulls and monsters are only active if they are visible on the screen. In other words, a monster in a remote part of the level will not move unless it becomes visible.
Players and weapon shots move one tile at a time in the same manner as the monsters. Each player can only have one weapon shot active at any one time. However, a weapon shot is lost if it hits any tile that is not a floor tile or goes off the screen, allowing a new shot to be fired.
Now that we have analyzed and described the game in a bit more detail, we need to look at how we will create a game in this style for the PC. For that we need to make some basic design decisions so we know how to start the programming.
We will run our game in a 640 x 480, 256 color screen mode. This is for two reasons: Firstly this mode is one of the best-supported screen modes across different PCs and secondly it allows us to use 32 x 32 graphic tiles instead of the original 16 x 16 while still keeping roughly the same scale.
We can easily get rid of the original 60 x 30 level size limitation for our version. Basically there are two ways we can do this:
- Since the game graphics are purely tiles and not sprites, we can use a tile map and scroll the screen by redrawing the tiles each time we need to scroll. This is memory efficient but can be quite slow, even with some optimizing to only draw new tiles.
- Alternatively since we are running in a pretty low-resolution mode by today's memory standards we can just use one large bitmap to contain all the level. Each 640 x 480 screen area will take up 300k, and so we could fit more than 100 ‘screens’ into 32 megabytes. Even if we use a square map of 100 x 100 level tiles (which is a lot bigger than the original levels), then this would still only take up 10 megabytes of memory.
To adopt the second method we would need much more memory, however even older PC’s probably have at least 64 megabytes. These PC's can also be quite slow in terms of processor speed, and so we will adopt the simplest and fastest method and use the large bitmap approach.
Now that we have sorted out the level view, we also need to store our map for the level. If we didn't have a map we would have no way of finding out the tile for each position in the level. The traditional method of storing a map is by using an array or by using pointers and a malloc'ed area of memory. However, instead we are going to use another bitmap to store out map!
There are some good reasons for this: first, by storing our maps on disk as pictures it becomes much easier for people to make level designs with their favorite paint program. So if we deal with the map internally as a bitmap, we avoid the need for two conversion routines between arrays and pixels when loading and saving maps.
Secondly, we can easily make a more flexible door opening routine if we use a bitmap. In the original game opening a door would open all connecting door tiles in a horizontal or vertical line. While we can easily make such a routine ourselves, we could also simply use Allegro’s Flood fill routine. This would save us writing any extra code, but also we can then have complex patterns of door tiles which we can open with one simple function call. This would also save us a lot of time and effort by not having to write a more complicated floodfill style routine for use on an our map data.
We will use simple structs for storing the player and other level information and the information taken from our map can be used for moving and generating monsters.
Now we have the basics of the design sketched out. In the next article we will create our first bit of programming and start to implement our design!