The Stickman Game Engine:
A Win32 API 2-D Game Engine
By: Nick Cash
of Major Features:
- Bitmap Support:
Bitmaps comprise all of the images in the game. They are simple to create and simple to work with. Problems creating this
feature including getting them to load as a resource, which proved difficult since the function wouldn't work. Also, the Win32
function TransparentBlt() turned out to act funky on some Windows machines, so it had to be replaced by a equivalent
function using BitBlt().
- Sprite Support:
Sprite's are one of the most powerful features of the engine. They can be anything from a projectile to a player character.
A "sprite" is basically an independent object that moves on the screen. It includes one of the more complex structures, as it
hold's everything from pointer's to the sprites bitmap, velocity, position, name, and animation information.
- Sound Support:
The engine support's two types of sound: MIDI and WAV. MIDI files are small and sound kind of funny, while WAV's are
like decompressed MP3's and tend to be very large. Since the Win32 API doesn't support WAV mixing on an easy level,
I opted to use the DirectX API's DirectSound capabilities. It allows me to allocate and play sounds as I wish. It also gives
me volume control and a few other features. Overall the DX API is bulky and ugly, like everything Microsoft produces, but
is useful and fairly efficient at its tasks. Possible improvements on this could include streaming audio, as allocating a 20MB
song drain's the memory pretty quick.
- Dynamic Background Support:
One night my mentor and I were talking and we decided that if the stars in the background twinkled it would be really cool.
So, I set out to program it. With the current set up, you can define any of three types of backgrounds: IMAGE, COLOR, and
STARRY. IMAGE uses a specified bitmap, color uses a specified RGB value, and STARRY will create between 1 and 100
twinkling stars. The system, with this set up, could easily be expanded to incorporate more dynamic backgrounds, such as
rotating planets or other types of animation.
- Level Scripting:
Perhaps the most annoying but needed feature is level scripting. This allows you to write a series of commands (the "script")
for the game to read, which will then be interpreted and used to create the level. This has a great advantage over hard coding
level's since you can then create levels externally and load them rather easily. With this comes several level management
features as well. The main two are population management and objects.
Population management tracks the number of a certain sprite on a level and will adjust the number accordingly. If there are
fewer then the specified level then it will add till it meets the requirement, if its in between the minimum and maximum it will
add at random follow this algorithm/conditional:
if ( random_number( population[MIN], population[MAX] ) == population[CURRENT] )
Also, if there are more sprites then the maximum number specified then it will remove until it hits the max.
Objects are anything that is draw in the level bitmap. Since level's are drawn as one image, it is needed to define each object,
which is definitely a pain. There are several types of objects that the game engine supports. This list is as follows: Solid,
Kill, Clim, Exit, Click, Move, Launch, None. It is these objects that make up the levels, and probably the things that matter
most. Any platform you stand on, and solid moving object, and pad that launches you high into the air. These are all objects.
- Log Support:
A great and useful feature of any game engine is logging. The ability to spot and find an error and record it is a great time saver
for the programmer. The engine employs two functions. Write_log() was written early on and isn't very advanced. It employs
the messy and annoying file interface of the Win32 API. It works, but you have to add all variables to strings before hand.
This later prompted me to write the game log function, which was shortened to glog(). This function will take any number of
parameters and will log the string accordingly. This is a time saver and a useful feature, as you then save yourself anywhere
from 2-5 lines of code. It also appears to be more efficient.
- String Handling:
For scripted levels you need functions to parse the string blocks. There are various functions that deal with string handling.
Read_word() will grab the first space terminated word it finds. Str_rep() will replace a given string with another given string.
Other's remove certain codes from a string, such as \n and spaces. Lastly, a function that dates back a long ways, is one that
checks to see if a string contains anything other then numerical digits. Very useful if you need a number, not "a" or some other
character of the alphabet.
- SMAUG's 32-bit structure
Borrowed from SMAUG, this system allows one integer to hold up to 32 values (0 - 31). This may not seem useful at first,
but you can't return multiple things sometimes, so its easy to designate bit values for them and return them all as an int and
analyze the number linearly.