Now we will be placing our letters representing the map into an auxiliary array so we can then draw it with a single printf() call. For this we will be declaring an array and a variable for the cell position in which we're going to place our map character inside the array.
char imageMap[4096]={};
// The assignment of empty
braces initializes all elements to 0
int nImageCursor = 0; // The position where we should place our next character
Then we will assign the characters representing the map in this array. For this we will assign the letter and increment the cursor to the next position like this: imageMap[nImageCursor++] = 'P'; // assign 'P' at imageMap[nImageCursor] then increment nImageCursorWe need to set a 0 value at the end of our map text so printf() and other string operations know that the text ends there, so once we finished to place our map characters into the array, we set the value for the cursor position to 0:
imageMap[nImageCursor] = 0; // a null char indicates the end of the character string or text
After that, we simply call printf() by sending our map image as parameter as follows: printf( "%s", imageMap ); // %s gets replaced by the imageMap string.This leaves our code at the draw() function looking somewhat like this:
// We're going to draw our map in the imageMap array. char imageMap[4096]={}; // the assignment of empty braces initializes all chars in the array to 0
int nImageCursor = 0; // The position where we should position our next character
for( int z=0; z< map.Depth; z++ ) // iterate over every row
{
for( int x=0; x< map.Width; x++ ) // iterate over every column for the z row
{
if( player.x == x && player.z == z )
imageMap[nImageCursor++] = 'P'; // draw the player as an ascii character else if( enemy.x == x && enemy.z == z )
imageMap[nImageCursor++] = 'E'; // draw the enemy else { // Replace the tile value with a space
character if the value is 0, otherwise the null character will terminate our
string and the map will display truncated. imageMap[nImageCursor++] = map.FloorCells[z][x] ? map.FloorCells[z][x] : ' '; // inline conditional is (condition ? value_if_true : value_if_false) } }
imageMap[nImageCursor++] = '\n'; // \n is the code character for "new line" inside a text. We use it to display the next cells in the next row.
}
imageMap[nImageCursor] = 0; // a null char indicates the end of the character string or text.
printf( "%s", imageMap ); // draw the map to the consoleNow that we have our display improved, we can start adding some controls to our player. We are going to do this during our update() step by checking the state of the arrow keys and changing the value of the player position accordingly:
if(GetAsyncKeyState(VK_UP))
gameObject->Player.z = gameObject->Player.z - 1; // decrease z by 1
if(GetAsyncKeyState(VK_DOWN))
gameObject->Player.z += 1; // increase z by 1
if(GetAsyncKeyState(VK_RIGHT))
gameObject->Player.x ++; // increase x by 1
if(GetAsyncKeyState(VK_LEFT))
gameObject->Player.x --; // decrease x by 1 Not that difficult, was it? So now let's enable more enemies into our game so it doesn't look so empty. For this we're going to replace our single SCharacter instance we used for the enemy with a template type called vector that comes with the standard library of the compiler. We need to include a new file in order to have access to vector's definition:
#include <vector> // so we can use the std::vector<> type.Now we can declare the player and our enemy list as part of our new SGame structure that will hold the game data:
struct SGame // holds game data
{
SMap Map; // declare a variable of type SMap
SCharacter Player; // Declare a variable of type SCharacter for the player
std::vector<SCharacter> Enemy; // Here we're going to store our list of enemies
};
Also we should add a new map layer for storing our enemies as part of the map structure:
struct SMap // The struct is a block of variables to be used to store our map information
{
int Width, Depth; // Declare Width and Depth variables which will hold the active map size
int FloorCells[MAX_MAP_DEPTH][MAX_MAP_WIDTH]; // 2-D Array representing the tile cells
int EnemyCells[MAX_MAP_DEPTH][MAX_MAP_WIDTH]; // Map that holds indices to the enemy list.
};We could use a new function in order to manage the setup of enemies, like this:
void setupEnemies( SGame* gameObject )
{
#define INITIAL_ENEMY_COUNT 4
for( int iEnemy=0; iEnemy < INITIAL_ENEMY_COUNT; iEnemy++ )
{
SCharacter newEnemy;
newEnemy.MaxPoints = { 100, 50, 1000000 }; // HP, MP and XP
newEnemy.CurrentPoints = { 100, 50, 0 };
newEnemy.x = rand() % gameObject->Map.Width; // random value between 0 and width-1
newEnemy.z = rand() % gameObject->Map.Depth;
gameObject->Enemy.push_back( newEnemy ); // copy the new enemy as a new element at the end of our enemy list.
}
};At the update function, we refresh the enemy layer of the map from the enemy list. For this we first clear the enemy layer with the INVALID_ENEMY value:
for( int z = 0; z < gameObject->Map.Depth; z++ ) // clear each row
memset( gameObject->Map.EnemyCells[z], INVALID_ENEMY, sizeof(int)*gameObject->Map.Width );Then we iterate through each enemy and place the index in the corresponding cell:
for( unsigned int iEnemy=0; iEnemy < gameObject->Enemy.size(); iEnemy++ )
{
gameObject->Map.EnemyCells[currentEnemy->z][currentEnemy->x] = iEnemy; // assign enemy index to the cell corresponding to this enemy
}Now only the display of the new enemy data is missing, and we can change our previous lines at draw() with these new ones, which check for a valid enemy index in the cell being rendered:
else if( gameObject->Map.EnemyCells[z][x] != INVALID_ENEMY )
imageMap[nImageCursor++] = 'E'+gameObject->Map.EnemyCells[z][x]; // draw the enemy The source code for this program can be read from http://code.google.com/p/gpftw/source/browse/trunk/Tutorial5/main.cpp
That's it for now, I hope you liked it. In the next tutorial we we'll be talking about SVN which we're going to use through the rest of the tutorials. See you there!
No hay comentarios:
Publicar un comentario