lunes, 16 de junio de 2014

Adding game data to our skeleton application.

Hi there!

Following we're going to see how to start adding game logic to our skeleton application seen in the previous tutorial.

For this we will add a variable holding a two-dimensional array of cells, which is declared as follows:

    int FloorCells[MAX_MAP_DEPTH][MAX_MAP_WIDTH]; // 2-Dimensional array of (int)eger numbers

We will also add two variables holding the actual size of the map. This can be done with:

    int Width; // Declare Width and Depth variables which will hold the active map size
    int Depth;


Where "int" tells the type of data that the variable will hold, and Width and Depth are the names of the variables. They can also be defined like:

    int Width, Depth; // Declare Width and Depth variables which will hold the active map size


And for holding all the map data under a single name which we can reference comfortably, we're going to declare a data structure holding all these variables and we're going to call it SMap (S for Structure):

struct SMap  // The struct is a block of variables to be used to store our map information
{
    int Width; // Declare Width and Depth variables which will hold the active map size
    int Depth;   
    int FloorCells[MAX_MAP_DEPTH][MAX_MAP_WIDTH]; // 2-Dimensional array of integers which can be accessed as FloorCells[y][x] and will hold values for representing the terrain
};


Then we can declare a new variable holding together all the contents of SMap:

    SMap gameMap;      // declare a variable of type SMap

Then for setting a value on a variable inside the structure we can do as follows:

    gameMap.Width = 32;      // Set a width value
    gameMap.Depth = 21;      // Same for map depth


We can also get the memory address where the data of gameMap is located:

   SMap* gameMapAddress = &gameMap;

Where * tells that the address points to a SMap structure, gameMapAddress is the name of the variable and & requests the memory address of the gameMap data.

After having our data architecture set up, we will need to store some data inside our map cells. For this we're going to iterate over each position and set the value to the corresponding position in our 2d array:

#define TILE_GRASS 0
    for( int z=0; z< gameMap.Depth; z = z+1 ) // iterate over every row
    {
        for( int x=0; x< gameMap.Width; x++ ) // iterate over every column for the z row
        {
           
gameMap.FloorCells[z][x] = TILE_GRASS; // initialize the (x,z) map cell to "grass"
        }
    }


Where  the for() statement will have a syntax such as:

for( a ; b ; c )
{
      // code block for each iteration

Where a, b and c are:
a. code to execute before start iterating.
b. condition to meet before each iteration. (otherwise end for( ) execution)
c. code to execute at the end of iteration.

We can set up a wall border in a similar way:


#define TILE_WALL 1
    // set a wall border
    for( int x=0; x<
gameMap.Width; x++ )   
       
gameMap.FloorCells[0][x] = TILE_WALL; // set all cells in the first row [0]    

After having everything set up, we will want to draw it on the screen. For this we're going to iterate over each cell and print it as follows:

    for( int z=0; z< gameMap.Depth; z++ ) // iterate over every row
    {
        for( int x=0; x<
gameMap.Width; x++ ) // iterate over every column for the z row
        {
            printf( "%c",
gameMap.FloorCells[z][x] ); // draw the contents of the cell at (x,z) as an ascii character
        }
        printf( "\n" ); // \n is the code character for "new line" inside a text. We use it to display the cells for the next z value in the next row of the display.
    }
You can find more about printf formatting codes with Google, because it's a well known standard function and it's documented everywhere.

In the following link is the complete code added to our skeleton application but I also pasted the code below because it's still small enough to fit in the page:

// from http://code.google.com/p/gpftw/source/browse/trunk/Tutorial3/main.cpp
 

#include <stdio.h>      // for printf()
#include <windows.h>    // for interacting with Windows

#define TILE_GRASS   0  // define some values to represent our terrain tiles
#define TILE_WALL    1
#define TILE_WATER   2
#define TILE_LAVA    3

#define MAX_MAP_WIDTH    256 // define a maximum size to our game map
#define MAX_MAP_DEPTH    256   

struct SMap // The struct is a block of variables to be used to store our map information
{
    int Width; // Declare Width and Depth variables which will hold the active map size
    int Depth;   
    int FloorCells[MAX_MAP_DEPTH][MAX_MAP_WIDTH]; // 2-Dimensional array of integers which can be accessed as FloorCells[y][x] and will hold values for representing the terrain
};

void setup( SMap* activeMap );  // Accepts as parameter an address pointing to an SMap
void update( SMap* activeMap ); // Accepts as parameter an address pointing to an SMap
void draw( SMap someMap );      // Accepts as parameter a copy of the contents of an SMap

int main( void ) // start application from here
{
    SMap gameMap;      // declare a variable of type SMap
    setup( &gameMap ); // call setup() and send the address of our gameMap as parameter

    int frameCounter=0; // declare a variable for keeping track of the number of frame since execution began, where "int" stands for "integer"
   
    while( true ) // execute block {} while what's inside () is true
    {
        printf("Current frame number: %i\n", frameCounter);

        update( &gameMap );     // update frame, send map address to update() call
        draw( gameMap );        // render frame, send copy of the data to be displayed by draw()
        if(GetAsyncKeyState(VK_ESCAPE)) // check for escape key pressed
        {
            break; // exit while()
        }
        Sleep(150); // wait some time to give visual stability to the frame
        

        frameCounter = frameCounter+1;
    };
  
    return 0; // return an int
}

void setup( SMap* activeMap ) // Accepts an address pointing to an SMap
{
    printf("- setup() called.\n");

    activeMap->Width = 32; // Set a proper width for our map, which has to be less than MAX_MAP_WIDTH
    activeMap->Depth = 21; // Same for map depth   

    for( int z=0; z< activeMap->Depth; z = z+1 ) // iterate over every row
    {
        for( int x=0; x< activeMap->Width; x++ ) // iterate over every column for the z row
        {
            activeMap->FloorCells[z][x] = TILE_GRASS; // initialize the (x,z) map cell to "grass"
        }
    }

    // set a wall border
    for( int x=0; x< activeMap->Width; x++ )   
        activeMap->FloorCells[0][x] = TILE_WALL; // set all cells in the first row [0]   
    for( int x=0; x< activeMap->Width; x++ )       
        activeMap->FloorCells[activeMap->Depth-1][x] = TILE_WALL; // set all cells in the last row [depth-1]   
    for( int z=0; z< activeMap->Depth; z++ )   
        activeMap->FloorCells[z][0] = TILE_WALL; // set all cells in the first column [0]   
    for( int z=0; z< activeMap->Depth; z++ )   
        activeMap->FloorCells[z][activeMap->Width-1] = TILE_WALL; // set all cells in the last column [width-1]   
};

void update( SMap* activeMap )    // Accepts an address pointing to an SMap
{
    printf("- update() called.\n");
};

void draw( SMap someMap ) // Accepts a copy of the contents of an SMap
{
    printf("- draw() called.\n");
    for( int z=0; z< someMap.Depth; z++ ) // iterate over every row
    {
        for( int x=0; x< someMap.Width; x++ ) // iterate over every column for the z row
        {
            printf( "%c", someMap.FloorCells[z][x] ); // draw the contents of the cell at (x,z) as an ascii character
        }
        printf( "\n" ); // \n is the code character for "new line" inside a text. We use it to display the next cells in the next row.
    }
};



What this program does is the following:
- Declares a variable of type SMap to hold data during the whole program execution.
- Calls setup() which writes data on our SMap instance.
- Starts calling update() and draw() on every iteration of the main loop until the escape key is pressed, then inside draw() prints all the map cells as console characters.

In the next tutorial I will explain how to debug the application with Visual Studio and pause the execution to analyze the program step by step, and after that we will be adding more logic for the update() step in order to make our program more interesting.

See you there!

No hay comentarios:

Publicar un comentario