Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Game Programming in C - For Beginners

4.78/5 (37 votes)
10 Oct 2013CPOL12 min read 840.2K   14K  
A brief introduction to game programming using C/C++.
This article is for anyone who is interested in game programming. I will take you through the basics of game programming. Here we are specifically focusing on the classic DOS games. I cover and give examples for: Determining Initial requirements, Developing an Interface, analyzing different elements of the game design in the program that we're going to make, and developing logic for Gameplay.

Game Programming

Before we actually jump into game programming, we need to know something called event driven programming. Event driven programming refers to that style of programming wherein the user of the application is free to choose from several options rather than be confined to a predetermined sequence of interactions with the program. Game programming is one common example of event driven programming. A game is a closed, i.e., complete and self sufficient formal system that represents a subset of reality. A game is a perfect combination of actions-reactions or event-responses where every response is based on the most-recently occurred event.

Elements of Game Programming

In general, a computer game has five elements:

  • Graphics
  • Sound
  • Interface
  • Gameplay
  • Story

Graphics

Graphics consists of any images that are displayed and any effects that are performed on them. This includes 3D objects, textures, 2D tiles, 2D full screen shots, Full Motion Video (FMV) and anything else that the player will see.

Sound

Sound consists of any music or sound effects that are played during the game. This includes starting music, CD music, MIDI or MOD tracks, Foley effects (environment sounds), and sound effects.

Interface

Sound consists of any music or sound effects that are played during the game. This includes starting music, CD music, MIDI or MOD tracks, Foley effects (environment sounds), and sound effects.

Gameplay

It encompasses how fun the game is, how immense it is, and the length of playability.

Story

The game's story includes any background before the game starts, all information the player gains during the game or when they win and any information they learn about character in the game. A story is an element of a game. The difference between a story and a game is that a story represents the facts in an immutable (i.e., fixed) sequence, while a game represents a branching tree of sequences and allows the player to create his own story by making choice at each branch point.

Though graphics plays an important role in game programming, in this article we're not going to emphasize upon graphics and sound element of a game. We shall be concentrating at elementary game programming through text based interfaces.

Game Design Sequence

Since game design requires one to explore one's artistic abilities, it cannot be formulated in a step by step process. However, there are certain technical steps that one needs to follow in one way or another.
These are:

  1. Determining Initial requirements.
  2. Develop Interface.
  3. Develop Interface.
  4. Develop Logic for Scoring points.

We will look at each of these in detail.

Interface is another very important aspect of game programming. The interface is the mode of communication between the computer and the player. Like any human language, it is the funnel through which the programmer must squeeze the avalanche of thoughts, ideas and feelings that he/she seeks to share with the fellow player. Interface will dictate what can or cannot be done. Interface is composed of input and output. While developing interface, the programmer should develop the static display screens and dynamic display screen. Static display is the screen which remains unaffected by the player's actions i.e., the input by the player. The dynamic display, on the other hand, is the screen which is governed by the player's actions i.e., the input by the player.

Examples of some static display screens are:

Game selection screens

What options are available to the player on the game startup? This describes what options are on the menu, how and where it appears on what screen, how the player gets there, and how he gets out.

Game start screen

What does the screen looks like at the beginning of the game, what are the startup parameters, where are the characters, etc? What messages, if any are on screen, and where? Intro music? Etc.

Since the dynamic screen vary as per the input given by the player, their descriptions are too many to be listed here. Some examples:

Message Screens

While developing interfaces, you also need to work on screens in response to legal actions of the player, by intimating that he/she is on the right track. Also, you need to work on the screens required to warn the player in case he/she commits an illegal move or action.

End of game message

These screens include messages and responses to questions like: What happens when the player loses? What happens when the player wins? What happens when the player get the high score? Where does the player go when the game is over? How does he start a new game?

This step involves developing a proper logic for gameplay. This requires the game-programmer to answer many questions in the form of program-code. These questions include: How is game played? What are the controls? What is the Game Goal? How is the player going to achieve the game goal? etc. In other words, we must say that since game represents an event-driven situation, the game-programmer i.e., you must specify or program everything that includes:

  1. Determining Initial requirements

    While writing a game program, after selecting the goal-of-game, one needs to determine its initial requirements. For instance, to write a game program for guessing a number, you need to decide about a way to generate the number, number of players involved, number of chances allowed to the player, a scoring methodology etc. Here we are not aiming at making you a professional game programmer, rather we are concentrating more at giving you an idea of writing simple or elementary game programs.

    General Description of Game: The general description of a game involves the general overview of the game, how it works, what happens on each level, etc. It describes all parts of the game from the player's perspective:

    • What he's supposed to know before he starts playing.
    • What he sees.
    • What he does.
    • His intended reaction to what he sees and does.
  2. Develop Interface
  3. Develop Logic of Gameplay
    • responses to the user/player's action.
    • responses to system events.
    • rules of the game.
    • if it's a two player game (if the computer is a player), then the computer's moves and actions.
  4. Develop Logic for Keeping Scores

    Developing logic for the scoring purposes is a subset of developing logic for the game play. For this, you must first decide the scoring policy that you're going to follow in your game. You're going to decide the maximum number of chances allowed, the scoring mechanism, whether it is tied to time or not, etc. During this phase, the milestone events are worked out and accordingly scoring (positively or negatively) is carried out.

    Milestone Events in a Game

    Every once in a while, the player needs to be rewarded (or penalized) somehow for reaching that point in the game. Each of these places where something special happens is called a Milestone Event. There are a gauge to let the player know he's on the right (or wrong) track, and will encourage (or discourage) him to keep going.

Now that we have discussed these different phases in game-development, let us not develop a simple tic-tac-toe game.

General Description of the game:

  1. It's a two player game so the program takes the name of two players and assign O and X to the players.
  2. Players enter their move turn by turn, into the box they choose.
  3. Program needs to assure that no box is overwritten.
  4. If the player tries to enter his/her move into the box that's already taken by the other player the the chance passes over to the other player.
  5. Program needs to run till a player wins, want to quit the game or until there are no moves left.
  6. After a player wins, program displays the message and will ask the player if he/she wants to play again.

Now let us analyze different elements of the game design in the program that we're going to make.

It's a two player game, so we need two variables to store their names and run a loop to ask for the player to enter their move turn by turn. So we need another variable to store the turn to see which player is to enter the move. Here are the variables:

C++
char name[2][30]; //double dimensional array to store names of the player
int chance; //to store the chance, to track which player is to enter the move

We need a function to handle the navigation to the boxes when the player presses arrow keys and hit the Enter button to enter his move in the box. We need another variable to track the current box the player is on at the movement. An array to store the values entered by the player. So here are the variables:

C++
int box; //to track the current box the player is on at the moment
char a[3][3]; //array to hold the actual values that player enter while playing
int navigate(char a[3][3], int box, int player, int key);
// to handle key presses and update the current box the player is on
// and to enter the move in to the box when player presses Enter.

Here in this function, char a[3][3] is the array that holds the moves. box is the box the player was on, and key is the key pressed.

Another variable is required to count the number of turns. There are nine boxes in total however the number of turns maybe more than nine because if the player tries to enter his move into a box that's already taken, then the chance passes over to the other player.

C++
int turns; // to count the number of chances

We need a function to put the move into the box chosen by the player and we need to make sure that we don't overwrite the value in a box:

C++
void putintobox(char a[3][3], char ch, int box);

Here a[3][3] is used to represent the boxes, ch is the character ‘O' or ‘X', and box is the box into which the value is to be entered. Now how would we know what character to put into the box? Well, this function is called by the navigate function mentioned above. So if the navigate function is called like this: box = navigate(a[3][3],3,0,ENTER);, then it means that player1(here player1-0, player2 is represented by 2) needs to enter into box 3. The putintobox function checks if the box is taken and enter the value in to the array that represents the boxes (a[3][3]), and calls another function showbox(char ch, int box) to show the character on screen in the specified box.

checkforwin checks if the player has won the game or not and boxesleft will check if all boxes are filled. We would need another variable to check if the player wants to quit the game so – int quit;.

In order to interact with the user, many messages are displayed. Also the player is told if he won the game or if it's a draw. The program will also ask if the player wants to play again. So in our program, the messages would be:

The logic of this program is to run a while loop that runs till a player wins, or all the boxes are filled up but no one won the game or if the user wants to quit. Now while the loop is running, the variable chance that tracks whose chance is it to enter the move is updated. A function will check what was the key what pressed by the user (user can enter only up, down, left, right or enter key) and moves the cursor to the specified box and enter the character assigned to the player into the array and displays that on the screen. It also makes sure that no box is overwritten. It the user tries to overwrite the box, chance is passed on to the other player as a penalty to the player who entered the wrong move. At the end of the program, the user is asked if he/she wants to play the game again.

  1. Initial requirements
  2. Developing Interface
    • Ask the name of the players.
    • Display whose chance is it to enter the move.
    • Display if a player wins or if it's a draw.
    • Display a message when the player wants to quit.
    • Display a message asking if the player wants to play again.
  3. Developing logic for Gameplay

Here is the list of functions we would need:

  • void showframe(int posx, int posy) - This function will show the frame of the Tic Tac Toe on the specified position.
  • void showbox(int ch, int box) - This function will show a specified character into the specified box.
  • void putintobox(char a[3][3], char ch, int box) - This function is used to write the character into the array and will call showbox(ch,box).
  • void gotobox(int box) - This function will take the cursor into the specified box.
  • int navigate(char a[3][3], int box, int player, int key) - This function will be used to track the box number the user is at while he is pressing the arrows keys on the keyboard. This will also get the box number in which the user wants to enter the character assigned to him/her.
  • int checkforwin(char a[3][3]) - Checks if the player wins.
  • int boxesleft(char a[3][3]) - To check how many boxes are left.

Details of the function: void showframe(int posx, int posy)

C++
//Function to show the Tic Tac Toe Frame
void showframe(int posx, int posy)
{

  int hr=196, vr=179; // These are ascii character which display the lines
  int crossbr=197;    // Another ascii character
  int x=posx, y=posy;
  int i,j;

  gotoxy(35,4); cprintf("TIC TAC TOE");
  gotoxy(35,5); for(i=0;i<11;i++) cprintf("%c",223);


  for(i=0;i<2;i++)
  {
    for(j=1;j<=11;j++)
     {
      gotoxy(x,y);
      printf("%c",hr);
      x++;p;    x++;
     }
    x=posx; y+=2;
  }
  x=posx+3; y=posy-1;

  for(i=0;i<2;i++)
  {

   for(j=1;j<=5;j++)
   {
      gotoxy(x,y);
      printf("%c",vr);
      y++;
   }
   x+=4;y=posy-1;
  }


  x=posx+3; y=posy;  
  gotoxy(x,y);
  printf("%c",crossbr);

   x=posx+7; y=posy;      
  gotoxy(x,y);
  printf("%c",crossbr);

  x=posx+3; y=posy+2;                    
  gotoxy(x,y);
  printf("%c",crossbr);

  x=posx+7; y=posy+2;         
  gotoxy(x,y);
  printf("%c",crossbr);

}

void showbox(char ch, int box)

C++
//Function to show the character in the specified box
void showbox(char ch, int box)
{
   switch(box)
   {
     case 1 :	gotoxy(_x+1,_y-1); printf("%c",ch); break; //1st box
     case 2 :	gotoxy(_x+5,_y-1); printf("%c",ch); break; //2nd box
     case 3 :	gotoxy(_x+9,_y-1); printf("%c",ch); break; //3rd box
     case 4 :	gotoxy(_x+1,_y+1); printf("%c",ch); break; //4th box
     case 5 :	gotoxy(_x+5,_y+1); printf("%c",ch); break; //5th box
     case 6 :	gotoxy(_x+9,_y+1); printf("%c",ch); break; //6th box
     case 7 :	gotoxy(_x+1,_y+3); printf("%c",ch); break; //7th box
     case 8 :	gotoxy(_x+5,_y+3); printf("%c",ch); break; //8th box
     case 9 :	gotoxy(_x+9,_y+3); printf("%c",ch); break; //9th box
   }
}

void putintobox(char a[3][3], char ch, int box)

C++
//Function to insert the specified character into the array
void putintobox(char arr[3][3], char ch, int box)
{
  switch(box)
  {

    case 1 :	if(arr[0][0] != 'X' && arr[0][0]!= 'O')
                { arr[0][0] = ch;
		          showbox(ch,1);
		        }
		        break;

    case 2 :	if(arr[0][1] != 'X' && arr[0][1]!= 'O')
		        { arr[0][1] = ch;
		          showbox(ch,2);
		        }
		        break;

    case 3 :	if(arr[0][2] != 'X' && arr[0][2]!= 'O')
                { arr[0][2] = ch;
		          showbox(ch,3);
		        }
		        break;

    case 4 :	if(arr[1][0] != 'X' && arr[1][0]!= 'O')
		       { arr[1][0] = ch;
		         showbox(ch,4);
		       }
		        break;

    case 5 :	if(arr[1][1] != 'X' && arr[1][1]!= 'O')
		        { arr[1][1] = ch;
		         showbox(ch,5);
		        }
		        break;

    case 6 :	if(arr[1][2] != 'X' && arr[1][2]!= 'O')
		        { arr[1][2] = ch;
                  showbox(ch,6);
		        }
	        	break;

    case 7 :	if(arr[2][0] != 'X' && arr[2][0]!= 'O')
     		    { arr[2][0] = ch;
		          showbox(ch,7);
		        }
		        break;

    case 8 :	if(arr[2][1] != 'X' && arr[2][1]!= 'O')
		        { arr[2][1] = ch;
		          showbox(ch,8);
		        }
		        break;

    case 9 :	if(arr[2][2] != 'X' && arr[2][2]!= 'O')
		        { arr[2][2] = ch;
		          showbox(ch,9);
		        }
		        break;
   }//end of switch
}

void gotobox(int box)

C++
//Function to show the curson on the box specified
//uses the position to check the coordinates
void gotobox(int box)
{
  switch(box)
  {
    case 1 : gotoxy(_x+1,_y-1); break;
    case 2 : gotoxy(_x+5,_y-1); break;
    case 3 : gotoxy(_x+9,_y-1); break;
    case 4 : gotoxy(_x+1,_y+1); break;
    case 5 : gotoxy(_x+5,_y+1); break; //5th box
    case 6 : gotoxy(_x+9,_y+1); break; //6th box
    case 7 : gotoxy(_x+1,_y+3); break; //7th box
    case 8 : gotoxy(_x+5,_y+3); break; //8th box
    case 9 : gotoxy(_x+9,_y+3); break;

  }
}

int navigate(char a[3][3], int box, int player, int key)

C++
//Function to handle the navigation
int navigate(char arr[3][3], int box, int player, int key)
{
   switch(key)
   {
     case UPARROW    : if( (box!=1) || (box!=2) || (box!=3) )
		               { box-=3; if(box<1) box = 1; gotobox(box); }
	                   break;

     case DOWNARROW  : if( (box!=7) || (box!=8) || (box!=9) )
		               { box+=3; if(box>9) box = 9; gotobox(box); }
		               break;

     case LEFTARROW  : if( (box!=1) || (box!=4) || (box!=7) )
		               { box--;  if(box<1) box = 1; gotobox(box); }
		               break;

     case RIGHTARROW : if( (box!=3) || (box!=6) || (box!=9) )
		               { box++; if(box>9) box = 9; gotobox(box); }
		               break;

     case ENTER      : if(player == 0)
			            putintobox(arr,'O',box);
		               else if(player == 1)
			            putintobox(arr,'X',box);
		               break;
    }//end of switch(key)

 return box;
}

int checkforwin(char a[3][3])

C++
int checkforwin(char arr[3][3])
{
  int w=0;

/*  0,0   0,1   0,2
    1,0   1,1   1,2
    2,0   2,1   2,2
*/
  //rows
  if((arr[0][0] == arr[0][1]) && (arr[0][1] == arr[0][2])) w = 1;
  else if((arr[1][0] == arr[1][1]) && (arr[1][1] == arr[1][2])) w = 1;
  else if((arr[2][0] == arr[2][1]) && (arr[2][1] == arr[2][2])) w = 1;

  //coloums
  else if((arr[0][0] == arr[1][0]) && (arr[1][0] == arr[2][0])) w = 1;
  else if((arr[0][1] == arr[1][1]) && (arr[1][1] == arr[2][1])) w = 1;
  else if((arr[0][2] == arr[1][2]) && (arr[1][2] == arr[2][2])) w = 1;

  //diagonal
  else if((arr[0][0] == arr[1][1]) && (arr[1][1] == arr[2][2])) w = 1;
  else if((arr[0][2] == arr[1][1]) && (arr[1][1] == arr[2][0])) w = 1;

  return w;
}

int boxesleft(char a[3][3])

C++
int boxesleft(char a[3][3])
{
   int i,j,boxesleft=9;

   for(i=0;i<3;i++)
    { for(j=0;j<3;j++)
      { if((a[i][j] == 'X') ||(a[i][j] == 'O'))
          boxesleft--;
      }
    }

   return boxesleft;
}

Now we have all the functions in place, we move on to the third step that talks about Presentation.

We have actually taken care of presentation in some of the above written functions, haven't we?

The ASCII character used in this program to display the vertical line is 179 and for horizontal line is 196. For a cross - 197. Check this website for more information about extended ASCII characters http://www.asciitable.com/.

You can even printout your ASCII table with a C program. Here is an example:

C++
#include <stdio.h>

int main()
{
    FILE *fh;
    int  ch;
     
    fh = fopen("ascii.txt","r");
 
    for(i=0;i<256;i++)
     fprint(fh,"\n%d - %c",i,i);
 
    fclose(fh);
    return 0;
}

Now we will talk about Exception Handling. Here in this program, we have kept it simple so nothing much to worry about here, however, we do take the name from the user. The array we use to store the name is of size 30. What if the user enters a string that is more than 30 in length? This would result in a buffer overflow. This may crash your program right away or produce unexpected results. To avoid this either we can write a function that would get a string from the stdin one by one and stops if Enter is pressed or if string is more than 30 OR we can use the inbuilt function known as fgets.

Finally, putting it all together:

C++
#include <stdio.h>
#include <conio.h>

int main()
{
    /*
      Declaration of variables used
    */
 
    showframe(12,25);
    printf("\nPlayer 1, enter your name:"); fgets(name[0], 30, stdin);
    printf("\nPlayer 2, enter your name:"); fgets(name[1], 30, stdin);
 
    printf("\n%s, you take 0",name[0]);
    printf("\n%s, you take X",name[1]); getch();
 
    clrscr();
 
    do
    {
       while(!enter)
       {
         if(khbit())
          ch = getch();
        
           switch(ch)
           {
             case UPARROW : box = navigate(a[3][3], box, player, UPARROW);
             .
             .
             .
           }
       }
       if(quit) break;
       //check if the player wins
       win = checkforwin(a);
    
     }while(!win)
 
    if(win)
    { .
      .
    }
 
    else if(quit)
    {    .
         .
    }
 
 return 0;
}

View the complete source code and executable to take a look at how the program works.

Here are some screenshots of the working executable for Tic Tac Toe:

Image 1

Image 2

Image 3

This article was not a complete fully fledged article for game programming but I hope that you gain something out of it. If you have any questions, please feel free to email me at shine_hack@yahoo.com

Source code for this program can be obtained at: http://techstuff.x10.mx/articles/.

Happy programming!

Shine Jacob (Enot): shine_hack@yahoo.com

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)