Game programming/Abstract Data Types

From Wikiversity
Jump to navigation Jump to search

Notice this page was automatically translated from Spanish. This will be fixed when the author wants to do it.

"A master in the art of life makes no much distinction between his work and play, his work and leisure, his mind and body, his education and recreation, his love and his religion. He just distinguishes which is which. Simply collecting his vision of excellence in every thing he does, leaving others to decide if he is playing or working. In his own eyes, he is always doing both." Anonymous

Requirements[edit]

  • C knowledge
  • To know what an abstract data type (ADT) is, and why using that approach is preferable to using several unlinked variables.
  • To know how to implement an ADT in C programming language
  • To learn how to modify data in an ADT through pointers.

Programming example[edit]

After this introduction to the tutorial, let's go inside the field of C language and data abstract types implementation.

The most important feature of C related to programming games is the creation of abstract data types (ADT). The ADTs are a higher level of abstraction after the basic types of language such as: int (whole), float (real), double (double precision real), char (characters). With the ADT can create new organizations that data in a game would be: sprites (all moving objects), states of sprites, records records, menus, buttons, animations, linked lists, players, levels, games , Events, etc..

To clarify this matter see this example:

 // Code 1.1
 // File includes.h 
 typedef struct _sprite 
 { 
  int x, y / / position in the world 
  int speed; 
  int angle; / / degrees angle to where it moves 
  int frame; / / Table of animation 
  int framespeed; / / velocity of animation (pictures) 
  int energy; / / Energy 
  // And so on
 } Sprite; 

As a remainder, typedef is the keyword for creating abstract types from a structure. This snippet creates the sprite type which has data position, speed, angle, box animation, animation speed and energy variables. To use this type you would do (in a program that already has a main() function)

 // Code 1.2 
 # include "includes.h" 
 … 
 void InitGame (void) 
 { 
  Sprite sprite; 
  sprite.x = 0; 
  sprite.y = 0; 
  sprite.speed = 0; // Initially is still 
  sprite.angle = 0; // Looking to the right 
  sprite.frame = 0; 
  sprite.framespeed = 10 // Change the animation every 10 frames 
  sprite.energy = 10; 
 } 
 … 

This feature sets a sprite modifying their data. A real program would initialize this from a file or would use different values for energy and framerates depending on the sprite, which would use different initialization functions. The important thing here is to understand which types of data can be used as the basic types: declared and then assigned values. The difference here is that Sprite is a type compound and thus to compare their data is needed the operator period (.).

Why do we use an ADT? Why not to use the loose (unstructured) variables?

This could be as follows:

 // Code 1.3 
 … 
 void InitGame (void) 
 { 
  int spriteX, spriteY; 
  int spriteSpeed; 
  int spriteAngle; 
  int spriteFrame; 
  int spriteFrameSpeed; 
  int energy; 
  spriteX = 0; 
  spriteY = 0; 
  spriteSpeed = 0; 
  spriteAngle = 0; 
  spriteFrame = 0; 
  spriteFrameSpeed = 0; 
  spriteEnergy = 10; 
 } 
 …

This is somewhat equivalent to the first fragment (Code 1.2). However, it possesses several flaws. The first one is that when we need several sprites (and we will need) we should have parallel arrays of the variables or have variables such as:

 ...
 int spriteX2, spriteY2; 
 ...

Which is by any standard unworkable if we have several types of sprites. The second thing is that the data is encapsulated in the Code 1.2, but in 1.3 it is loose. The advantage to having the data encapsulated is that if we need to do something with the data we have to spend only a Sprite pointer, as follows:

 // Code 1.4 
 // A feature that takes away a point energy to a sprite 
 void DamageSprite(Sprite * sprite) 
 { 
  sprite->energy -= damage; 
  // Check if the sprite ceased to exist 
  if (sprite-> energy == 0) 
  { 
   // The sprite is dead, do something 
   PlaySound ( "muerto.wav"); 
  } 
 } 

This function is very simple. Get a pointer to a sprite and it diminishes their power at one point. To modify the data we use the sprite operator -> (arrow). What makes this operator is to dereference Sprite to access their data (it is as if we were to:

(*sprite).energy -= damage;

This is what is called pass by reference in C. You can also simple as int rates:

 // Código 1.5
 void swap(int *px, int *py)
 {
  int temp ;
  temp = *px ;
  *px = *py;
  *py = temp ;
 }
 // the call
 void doswap()
 {
  int x , y;
  x = 1 ;
  y = 2 ;
  swap(&x, &y) ;
  // En x queda 2 y en y 1
 }

What makes the role swap is to exchange values of x, and by reference. If passed by value values remain unchanged. To use the reference operator * use and modify the original values. That is what makes (*sprite).energy or, in abbreviated form for a TAD: sprite->energy.

Remember:

We use a TAD for not using parallel arrangements and to encapsulate the information in a single type. With that we can have arrangements Sprite.

All of the above join in the following code. If you did not understand some code earlier advise you to return and check to understand this block longer.

 // Código 1.6: Sprites arrays
 // Archivo sprites.c
 #include "includes.h"
 // Diez tipos de sprites
 #define MAX_SPRITES	10
 // Array of sprites
 SPRITE sprites[MAX_SPRITES];
 // The function to initialize them
 void InitSprite(SPRITE * sprite)
 {
  sprite->x = 0;
  sprite->y = 0;
  sprite->speed = 0;		// Inicialmente está quieto
  sprite->angle = 0;		// Mirando a la derecha
  sprite->frame = 0;
  sprite->framespeed = 10;	// Cambiar cada 10 cuadros
  sprite->energy = 10;
 }
 void InitSprites()
 {
  int i;
  for(i = 0; i < MAX_SPRITES; i++)
  {
   InitSprite(&sprites[i]);
  }	
 }
 void InitGame(void)
 {
  ...
  InitSprites();
  ...
 }

This code closes this chapter. My style is to enter the field from the start so that the reader curious about what can be achieved as soon as possible. If they found very difficult to advise you to review the key concepts of C-pointers, structures, step by reference, etc.. If you have not understood do not worry because the other chapters will be clarified the concepts outlined here.

Exercises[edit]

1. Show the code to declare a TAD animation. An animation must have a displacement x, y (a BMP file in which all are), a pointer to bmp (type SDL_Surface), width, height, number of tables animation.

2. Show the code for declaring a player named Player of TAD. Must have lives, score, color, name and sprite (sprites) partner. Hint:

 typedef struct _player
 {
  int score;	
  // Escribir el resto de campos
 } PLAYER;

3. Declare and initialize a list of under 4 players. Lives, score and color should be 0 at all. The name of each should get out of a settlement (char * names [4]). The sprite must emerge from an array of sprites (Sprite sprites * [4]);

4. Declare a variable pointer of a player to create a dynamic array of players. The function will receive the number of players, dynamically allocate the memory and initialize all fields to 0 (Hint: use the functions of memory management found in mem.h)