Intro

A lot of people have emailed me asking how I make games. So I've decided to start this page to help people get underway. Hopefully this page will help you make some games, if it does please email me and tell me about your game.

BTW this page is going to cover making DOS games only =)


Learning a Programming Language

The first thing you need to do is learn a programming language. I strongly suggest learning C. For one thing C is a great language for programming games, a lot of languages are very closely related to C, and many helpful tools are written in C or some form of it.

One good way to learn C is to read some books. There are many books out there but I'm going to have to recommend C for Dummies. This book is great, everything is explained excellently in the books. There are two volumes to get of this book. Some areas of C are not covered to closely in the book however you can easily pick up the material later, either through trial and error (like me =) or find some more information some other place.

After reading these books you should feel very comfortable working in C.


Picking a Compiler

The next thing you need to do is pick a compiler to make your game on. Several things will effect your choice, however it's probably just a question of money. Different compilers might have different function names, memory handling is a little different etc. Anyway the compiler I use is Watcom 10.6. However if you don't have enough money or don't want to buy it, there are free 32 bit compilers available. 32 bit meaning you're not going to run out of memory.

 

Programming Concepts

Even if you read all those C books, they're not going to teach you programming concepts. Top Down Design is the most important one. It's basically breaking problems into smaller parts to make advanced problems more simple and computer code easier to follow.

I hope by now you're not writing programs with your whole program in main(). I used to do this when I first started and trust me, it's a big mistake!! It is a very good idea to break your program into many functions.

Another good idea is to put all related stuff into different C FILES. For example all your scrolling functions should go in Scrolling.C & Scrolling.H. Don't have everything in one big source code file.

Don't ever be afraid to restart, throw out all your old source code. Every time you do something you learn and the next time you will probably do a better job.

There is always a better way!

 

Using Libraries

When first starting out I really don't recommend using libraries. You should learn to code without libraries first and then use them when needed. A good time to use a library is when there is no standard. A good example is with sound. There are so many sound cards out there making drivers for everyone or just some of them is going to take way too much of your time. This is a good time to use a library. Using libraries for Initialization is just fine but using them to do things during your game is a bad idea. There is a video standard and it's called VESA. I really think you use your own code anytime you draw to the screen. The more libraries you use the harder your code will be to follow.

Without Libraries:

DrawImage();
ShowScreen();
KeyPress();

With Libraries:

JoeSKicKinGfXDrAwIt(NULL,11,3,PUTINFORFUN);
SallyIsMeWifESaYSBrINGoUTSTAKE(NuLL,*EAT,HELLO);
Input78NPreSSOK(STARKEYS);

Now why would you want that in your code? Although that code isn't as bad as Windows programming =). If you're going to use a library make sure you get the source with it, and at least look at the code and try to understand it.

Re-Writing Code is a good idea. For example, usually sound libs don't have a very simple interface for playing sounds. I like to have it really nice and simple so I usually combine functions until I get something like:

InstallSound();
PlayMusic("mysong.mid");
StopMusic();
PlaySound("mysound.snd");
RemoveSound();

Doing this kind of thing makes your code a lot easier to read.


Game Design

Before you start coding your game you should definately think about what you want your game to be like. Setting limitations is something you're going to have to decide before you start. Will this game have 256 colors or 16 million? Choose what video mode to use. Take into account that you're choices are going to effect your game a lot. It's not a good idea to code your game for every possible situation, it can slow down your game to do this. This is not to say, give the player no choices, just set good limits for your game. Like how many enemies on the screen at once etc.

Plan your game engine before you start.


Tools & Editors

It's now time to decide what tools or editors are going to make the development of your game faster. Will you code them? Or use something someone's already made? The choice is up to you, but if you use someone else's editor it will lack customization to your game. Something that most games will need is a map-editor. Making this will definitely speed up the development of your game. Other tools should also be made as well.


Game Engine

This stage is the longest one, it's basically just coding your game. It's important to use code you've made before in your game. Maybe your Font engine, or your gfx code etc, use what you can to speed up making your game.


Bugs & Errors & #$@#$! Argh!?

No one likes it when things go wrong but they do. Just relax take a break (or take none) and look at your code. Asking someone else to look at your code is a good idea, it's sometimes hard to see your stupid but simple how could I have been so stupid mistakes. There is really only two different kinds of Errors. The first is, I know what I'm doing and this shouldn't be happening. This is probably just a dumb mistake you've made, but often very hard to spot in your code what you're doing wrong. The other one is, I'm not to sure what's going on I hope it works. There's really nothing you can do except ask someone about your problem or do some trial & error.

Some things to watch for are:

Going past arrays. int n[50]; n[60]=1;
Copying past the limit. char *n = (char *)malloc(100); memcpy(n,buffer,200);

These are the most common things that can go wrong. Don't be afraid to step through your code line by line like the computer does.


Sample Code Main()

Here is some sample code for a main() function in a game. This code is taken from MarioPC Version 3. Can you see how using a library makes the code harder to understand? (XLiB)

void main()
{

long size=0,zx; unsigned long start_time=0,end_time=0,frames=0;
float fps=0; int z;

Mario.counter=0;
LoadLevel("test.lev");
LoadBack("cool.lev");
LoadMTiles(); LoadBTiles();
InitMario();


for(zx=0;zx<50;zx++)
{
size=x_sizeof_cbitmap(88,mtiles[zx].data);
tiles[zx]=farmalloc(size);
x_compile_bitmap(72,mtiles[zx].data,tiles[zx]);
}

for(zx=0;zx<8;zx++)
{
size=x_sizeof_cbitmap(88,mariopic[zx]);
mario[zx]=farmalloc(size);
x_compile_bitmap(72,mariopic[zx],mario[zx]);
}

for(zx=0;zx<40;zx++)
{
size=x_sizeof_cbitmap(88,back[zx].data);
cback[zx]=farmalloc(size);
x_compile_bitmap(72,back[zx].data,cback[zx]);
}


x_text_mode(); /* make sure VGA is in color mode, if possible */
x_set_mode(13,256+32);
x_put_pal_raw(mariopal,256,0);

x_set_doublebuffer(240);
x_rect_fill(0,0,288,272,HiddenPageOffs,26);

DrawScreenBack();
DrawScreenWorld();

x_page_flip(0,0);
while(StartAddressFlag);
x_page_flip(16,0);
while(StartAddressFlag);
wx=0;

InstallKeyboardDriver();

start_time=clock();
while(!checkKey(KEY_ESC))
{
UpdateJoystick();

DoMario();

x_rect_fill(0,0,288,272,HiddenPageOffs,26);
DrawScreenBack();
DrawScreenWorld();
DrawMario();
x_page_flip(16,0);

while(StartAddressFlag);
frames++;
if(Mario.y>224) break;

}
end_time=clock();

x_text_mode();
RemoveKeyboardDriver();

fps= (frames * CLK_TCK) / (end_time-start_time) ;
printf("Frames per second=%f",fps);

}


Basically I just wanted to slow you that your main() should be this:

void main()
{

Initialization();
GameLoop();
ShutDown();

}


Video Mode

No matter what video mode you choose for your game you still are going to have to set the video mode and then set it back when your done in your program.

SetVideoMode(mymode);
DoGame();
SetVideoMode(textmode);

Setting the video mode is part of your Initializing stuff. Here is a function to set the video mode in Watcom 10.6:

extern void SetMode(int);
#pragma aux SetMode ="int 10h"\
parm [eax];

To set the video mode to 320x200x256: SetMode(0x13);
To set the video mode to text-mode: SetMode(0x03);
These are basic VGA modes and every video card out there supports them.


Memory

This is a really important topic. You've got to feel comfortable dealing with memory to program games, especially gfx. Here is how to allocate some memory in C:

char *mem;

mem = (char *)malloc(10); // This allocates 10 bytes for mem

Now mem is just like:

char mem[10];

To free the memory:

free(mem); // Simple eh?


Memcpy & Memset

These are very useful functions I use them all the time. Here's how they work.

#include <string.h>

memcpy( DESTINATION , SOURCE, LENGTH );
memset( DESTINATION , VALUE2SET, LENGTH );

Lets create to memory buffers, set one to one value, and then copy that buffer to the other one.

char *buffer1, *buffer2;

1) buffer1 = (char *)malloc(10); // Create the first buffer
2) buffer2 = (char *)malloc(10); // Create the second one
3) memset(buffer1,5,10); // Set all the values in buffer1 to 5
4) memcpy(buffer2,buffer1,5); // Copy 5 bytes of buffer 1 into buffer2

What's going on?

When we allocate memory the values are going to be random. So buffer1 could contain 2,233,4,40,5,2,3,4,5,100. So lets say after doing line #1 buffer1 contains:

X,X,X,X,X,X,X,X,X,X // Random Values

1) Allocating 10 bytes of memory for buffer1. ( b1 = X,X,X,X,X,X,X,X,X,X )
2) Allocating 10 bytes of memory for buffer2. ( b2 = X,X,X,X,X,X,X,X,X,X )
3) Set 10 bytes of buffer1 to 5. ( b1 = 5,5,5,5,5,5,5,5,5,5 )
4) Copy 5 bytes of buffer1 into buffer2. ( b2 = 5,5,5,5,5,X,X,X,X,X )

Alternatively we could have done this: (Without pointers)

char buffer1[10],buffer2[10];

1) Don't need this anymore
2) Don't need this anymore
3) memset(buffer1,5,10); // Set all the values in buffer1 to 5
4) memcpy(buffer2,buffer1,5); // Copy 5 bytes of buffer 1 into buffer2

I hope you feel comfortable working with memory now. The following should make sense to you:

char name [] = "Noname" ;
char myname [] = "Nathan";

memcpy(name,myname,6);
printf("The name is now: %s",name);

This prints "Nathan" on the screen. See how we copied myname into name?


Accessing the Video Screen Part One

When we set the video mode to 320x200, you can easily make a pointer to the screen. A pointer meaning a memory location. Then the video screen acts as 64000 bytes (320x200) of unsigned chars. (Unsigned Char is a value from 0 - 256). That's where we get 256 colors from.

Making a pointer to the screen in 320x200x256: (Watcom Code)

char *VGA = (char *)0xA0000; // Make that pointer.

The 256 values that we can set on the video screen are all different colors. It is called the palette. We can set the palette. We'll learn more about this later. The standard for palettes is that Color 0 is black, and Color 255 is white. This is how you set the screen to white:

1) char *VGA = (char *)0xA0000; // Make that pointer.
2) memset(VGA,255, 320*200 ); // Set the screen to white.

Remember we must set the VGA pointer to equal the video screen before we access it! Or your program will crash! Because you are setting some random memory location to 255 for 64000 bytes. That's going to overwrite something important in memory.

What's going on?

1) Setting up the VGA pointer to be equal to the start of the video screens memory.
2) Set the video screen to the value 255 (which is white by default) and set 64000 bytes to this value. 64000 = 320 * 200. Which is the size of the video screen in the mode we're working in. I could have wrote 64000 instead of 320*200, which would be faster but I wanted to show you 320*200, so you wouldn't be wondering where 64000 came from.


How the Your Monitor Works & Shearing Effect

How come setting the Video Cards memory to 255 makes the screen all white? How does the computer know I've changed what's on the screen? Well it doesn't. What happens is you computer constantly copys the VideoCards memory to the actual screen. Taking a short break in between each copy. This is called the Vertical Retrace. Meaning Redrawing the screen. Have you ever ran a program where the screen seems to split slightly or get invisible lines when it scrolls? That's what happens when you copy to video memory when the Computer is trying to redraw it to the monitor at the same time. Half the screen is the new one, and half is the old one.

What can we do about this? All you have to do is wait for the screen to finish drawing before you draw to the screen. You make a simple function that does this. Here is the code for it.

void WaitRetrace(void)
{
while(inp(0x3DA) & 0x08 );
while(!(inp(0x3DA) & 0x08 ));
}

Don't worry about how it works, just remember it does work and to call this function before you draw to the screen it you want to avoid shearing. By the way, waiting for the retrace slows down your game to the monitors refresh rate. This is ok however, because it allows you to achieve exactly 60 frames per second in your game. Even if someone has a really fast computer the game will still run at the same speed.

Here is code to set the screen to white but avoid shearing:

1) char *VGA = (char *)0xA0000; // Make that pointer.
2) WaitRetrace();
3) memset(VGA,255, 320*200 ); // Set the screen to white.

Notice the code is basically the same except we wait for the retrace to avoid shearing. We really only need to Wait for the Retrace when we are constantly updating the screen, which you are probably going to be doing in your game.


More to Come, Stay Tuned....

 





All graphics, styles etc, Copyright (c) 1998 Firebell.
No part of this web page may be copied without permission.