Alex Russell's Dos Game Programming in C for Beginners

Introduction . Chapter 1 . Chapter 2 . Chapter 2.1 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6

Chapter 1

Quick overview of C

I am assuming you are already comfortable programming in c. This chapter is meant to be a quick over view of commonly used programming techniques in dos games. If everything here is not familiar I suggest you seek out a good c tutorial.

Pointers

Games use lots of memory, and most of it is accessed via pointers. Pointers are fast and, once you learn how they work, simple.

A pointer is a variable that holds the address of a data item. c pointers have an associated type, and generally only point to one type of thing.

char *t1;

This declares a pointer to a character. It does NOT define where it points.

char *t1;
strcpy(t1, "hello world");

This will crash many computers. We have declared the pointer t1, but we are now trying to copy data to it, BEFORE we make it point to a valid range of memory.


char *t1;
t1=malloc(100);
strcpy(t1, "hello world");

This will work. We have declared t1 to be a pointer to memory holding characters. We have made t1 point to a valid range of memory,100 bytes long, using the function malloc(). Then we have copied the data "hello world" to the memory t1 points to.

malloc() is a function that returns a pointer to a range of memory that your program can safely write to. It takes one parameter which specifies the number of bytes we want. It returns NULL if the requested memory is not available.

int *it1, *it2;
int i;

it1=malloc(100*sizeof(int));
it2=it1;
for ( i=0; i < 100; i++ )
	{
	*it1=i;
	it1++;
	}

This code makes it1 point to a range of memory large enough to hold 100 integers. The operator sizeof returns the size in bytes of a C data type. Then the memory pointed to by it1 has the values set to 0 through 99.

*it1=i;

The '*' 'dereferences' a pointer. *it1 means 'the value pointed to by it1'. This line of code sets the integer that it1 is pointing to to the value of I.

i=*it1;

This line of code sets i to the value of the integer that it1 is pointing to.

i=it1;

This line of code sets i to the value of the ADDRESS that it1 is currently pointing to.

it1++;

This makes it1 point to the next integer.

it1+=5;

This makes it1 point to the 5th integer from where it is now. The c compiler knows what the pointer is pointing to and automatically adjusts how far it moves pointers by the size of the data it is pointing to.

typedef struct
	{
	char s1[90];
	int I,j,k;
	}
data_t;

	data_t data, *dp;

	strcpy(data.s1, "hi there");
	data.i=1;
	data.j=2;
	data.k=3;

	dp=malloc(sizeof(data_t)*100);

	strcpy(dp->s1, "bye know");
	dp->I=7;
	dp->j=8;
	dp->k=9;

	dp++;
	memcpy(dp, &data, sizeof(data_t));



Here we have defined a struct of type data_t, and declared a data_t, and a pointer 
to a data_t. dp->i; means the value of member i of the struct that dp points to. It is 
short hand for *(dp.i); The memcpy() copies data to dp.

int foo(int x, int y)
{
	return y*320 + x;
}

This is a very simply function that takes two integers as parameters, and returns an integer. If this is not a very familiar concept I suggest you seek out a c tutorial.

#include <stdio.h>

The above line `includes' stdio.h in the source code. It is exactly the same as inserting the file stdio.h in the source file. Include files should never contain code or definitions (e.g. global variables). Only declarations, prototypes, defines, etc. should be in include files. When making your own include files the following code should go at the top and bottom to prevent it from being included more than once. It is a common practice to have an include file include all the files required to make it compile correctly. This can lead to the same file being included more than once if you do nothing to prevent it.

/* test include file */
#ifndef DEF_TEST
#define DEF_TEST 1

typedef unsigned char BYTE;

#endif

The #ifndef, #define, and #endif together will prevent an include file from being included multiple times. Simply change the DEF_TEST to DEF_filename for each include file.

The standard c runtime functions fopen(), fwrite(), fread(), fseek() etc. will be used for most file i/o in these examples. If these functions are not already familiar then I suggest you seek out a C tutorial. You should be comfortable reading existing files, and writing out new files.

We will be using the MEDIUM memory model which is NEAR data, and FAR code. This means that the use of the far heap will require the use of farmalloc() and farfree().

In general, global variables, and goto's are BAD, but we will use a few global variables where it makes sense.

While most of the basic graphic and animation techniques presented here are generic enough to be useful in any project, the user i/o (keyboard, mouse, joystick) is so specific to DOS that I will present the code to do it with minimal explanations.

Entering mode13h, via int86

This course will be using mode13h exclusively. This is 320x200, 256 colours. Video memory is laid out in a simple rectangular grid where 0,0 is at the top left, x increases to the right, and y increases down. Each pixel is one byte, and its colour is determined by the colour palette it indexes. Mode 13h has a colour palette of 256 colours, each of which is defined by 6 bits of red, blue, and green.

Pixel coordinates are always presented as a pair of numbers indicating the X and Y position of the pixel. For example, the black pixel above is at location (3,1) Please note that the top left corner is (0,0) NOT (1,1). The bottom right pixel is (319, 199). This linear arrangement of video memory is common to most modern video systems. While it is natural to think of video memory as a grid like this, it is actually just a long array of memory. More on this later.

Code to enter mode13h.

int old_mode;

void enter_mode13h(void)
{
	union REGS in, out;

	// get old video mode
	in.h.ah=0xf;
	int86(0x10, &in, &out);
	old_mode=out.h.al;

	// enter mode 13h
	in.h.ah=0;
	in.h.al=0x13;
	int86(0x10, &in, &out);
}

void leave_mode13h(void)
{
	union REGS in, out;

	// change to the video mode we were in before we switched to mode 13h
	in.h.ah=0;
	in.h.al=old_mode;
	int86(0x10, &in, &out);
}

Chapter 1 Exercises

1. What does this do:

int i;
int *p;

p=malloc(100*sizeof(int))
for ( i=0; i < 100; i++ )
	*p++=i;

2. Write a function that returns 0 for even numbers, and non-zero for odd numbers.

3. Write a function to reverse the contents of an integer array. Do not use pointers.

4. Write a function to reverse the contents of an integer array using pointers.

5. Write a function to return the larger of two integers.

6. Write a function to swap the value of two integers, use this prototype:
void swap(int *x, int *y);

7. Write a function to fill an array of integers with even numbers using a `for' loop.

8. Write a function to fill an array of integers with odd numbers using a while loop.

9. Write a function to allocate 100 bytes of memory, and set it to the letters of the alphabet. When you reach Z, start over at A until you reach 100.

10. Write a function that copies a file using a 1Kb buffer allocated with malloc. Include error checking.

Chapter One has no source code.

Introduction . Chapter 1 . Chapter 2 . Chapter 2.1 . Chapter 3 . Chapter 4 . Chapter 5 . Chapter 6

Copyright 1998 (c), Alex Russell, All rights reserved