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
Pointers
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;
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.
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.
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.
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.
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.
Chapter 1 Exercises
1. What does this do:
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:
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
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.
Games use lots of memory, and most of it is accessed via pointers. Pointers are
fast and, once you learn how they work, simple.
strcpy(t1, "hello world");
char *t1;
t1=malloc(100);
strcpy(t1, "hello world");
int *it1, *it2;
int i;
it1=malloc(100*sizeof(int));
it2=it1;
for ( i=0; i < 100; i++ )
{
*it1=i;
it1++;
}
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;
}
/* test include file */
#ifndef DEF_TEST
#define DEF_TEST 1
typedef unsigned char BYTE;
#endif

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);
}
int i;
int *p;
p=malloc(100*sizeof(int))
for ( i=0; i < 100; i++ )
*p++=i;
void swap(int *x, int *y);