Table of Contents Source Code Article Three Article Five
In the last two articles, We've gone through how to create a map system and how to create an even better map system. Sick of them yet? Well let's see about making them a little more interesting. In this article, we'll discuss how to interact with the map to make it become a little more alive.
This is a short and sweet article that shows you how to actually use the map engine you've made. The point I want to get across is that your map doesn't have to be static and lifeless. We're going to do this by adding an "open/close door" command to our game. Don't laugh. Well, okay, don't laugh too hard. Simple little tricks like these really increase the interactivity and depth of your game.
The idea is that we're going to add the 'o' key to the mix, which changes closed doors to open ones; and then creating a 'c' key command which changes open doors back to closed ones.
First thing we need to do is to detect these keypresses. Inside the switch..case statement we'll add the following cases:
// Open door
case 'o':
// do stuff
break;
// Close door
case 'c':
// do stuff
break;
Now we need to think for a second: we're actually opening a door located at a tile adjacent to the player's position. Which leaves us with a conundrum: how to we know which direction the door is? What if there's more than one door nearby? Which one does the user want opened?
There's an easy solution to this problem; we can simply ask the user the direction they want. That being the case, there's going to be a bit of code to pull that off - more than what would be clean and tidy inside a case statement. So, let's put it into a function:
void CloseDoorCommand( void );
void OpenDoorCommand( void );
And later on:
// Open door
case 'o':
OpenDoorCommand();
break;
// Close door
case 'c':
CloseDoorCommand();
break;
So now we can focus on what needs to be done in these functions. First thing we need to do is ask the user where they want to use the command, which looks eerily familiar to the main input loop.
// OpenDoorCommand Function //////////////////////////////////////////////////////////////
//
// User command function which and then attempts to convert a closed door to an open one
// at the tile specified by the user.
//
void OpenDoorCommand( void )
{
// Draw some notification to the user
console.SetPosition( 2, 22 );
console << "Which direction? (2,4,6,8)";
// Let the user decide where to look
char nKey = getch();
int nDeltaX = 0;
int nDeltaY = 0;
switch( nKey )
{
// SOUTH
case '2':
nDeltaX = 0;
nDeltaY = 1;
break;
// WEST
case '4':
nDeltaX = -1;
nDeltaY = 0;
break;
// EAST
case '6':
nDeltaX = 1;
nDeltaY = 0;
break;
// NORTH
case '8':
nDeltaX = 0;
nDeltaY = -1;
break;
// Not a valid direction
default:
// No direction specified, so abort
return;
}
}
Next, we get to the actual meat-and-potatoes of what we're trying to accomplish. What we need to do is check to see if there's a closed door at the tile adjacent to the player. If there is, then we change it's type to an open door. If not, then do nothing.
The catch to this problem is that this function doesn't know the coordinates of the player. The main() function does, but not this one. What to do? Normally, the proper way to do this is to pass the player's coordinates as parameters to this function. But, given that the entire game revolves around the player, and it's foreseeable that many, many more functions would need this data, I would advise to make the nPlayerX and nPlayerY variables global. Some people might disagree with this notion, but given the player-centric nature of our design it's just one less thing to bother ourselves with.
// Is there a closed door present in the direction specified?
if( nMapArray[nPlayerY + nDeltaY][nPlayerX + nDeltaX] == TILE_CLOSEDDOOR )
{
// If there is a closed door, change it to an open one
nMapArray[nPlayerY + nDeltaY][nPlayerX + nDeltaX] = TILE_OPENDOOR;
}
Just one last thing left. Because we're adding some text to the screen when we ask the user, it hangs around if we don't get rid of it. In the interests of keeping our user interface clean, add this just after the user enters a key.
// Clear the screen to get rid of the notification text
console.Clear();
That's it. The complete source for the OpenDoorCommand function looks like this:
// OpenDoorCommand Function //////////////////////////////////////////////////////////////
//
// User command function which and then attempts to convert a closed door to an open one
// at the tile specified by the user.
//
void OpenDoorCommand( void )
{
// Draw some notification to the user
console.SetPosition( 2, 22 );
console << "Which direction? (2,4,6,8)";
// Let the user decide where to look
char nKey = getch();
int nDeltaX = 0;
int nDeltaY = 0;
// Clear the screen to get rid of the notification text
console.Clear();
// Compute which tile the user specified
switch( nKey )
{
// SOUTH
case '2':
nDeltaX = 0;
nDeltaY = 1;
break;
// WEST
case '4':
nDeltaX = -1;
nDeltaY = 0;
break;
// EAST
case '6':
nDeltaX = 1;
nDeltaY = 0;
break;
// NORTH
case '8':
nDeltaX = 0;
nDeltaY = -1;
break;
// Not a valid direction
default:
// No direction specified, so abort
console.Clear();
return;
}
// Is there a closed door present in the direction specified?
if( nMapArray[nPlayerY + nDeltaY][nPlayerX + nDeltaX] == TILE_CLOSEDDOOR )
{
// If there is a closed door, change it to an open one
nMapArray[nPlayerY + nDeltaY][nPlayerX + nDeltaX] = TILE_OPENDOOR;
}
// Clear the screen to get rid of the notification text
console.Clear();
}
That's really pretty much it. To do the 'c'lose door command, you can copy this function, changing the latter part of the source to the following:
// Is there a closed door present in the direction specified?
if( nMap[nPlayerX + nDeltaX][nPlayerY + nDeltaY] == TILE_OPENDOOR )
{
// If there is a closed door, change it to an open one
nMap[nPlayerX + nDeltaX][nPlayerY + nDeltaY] = TILE_CLOSEDDOOR;
}
Not much is different, except that the TILE_OPENDOOR and TILE_CLOSEDDOOR constants are reversed.
Yes that's pretty much it. Any changes to the map data will be drawn to the screen at the beginning of the next game loop, displaying the changes made by the user. By changing tile types, the user can change closed doors to open ones and walk through a previously blocked tile.
Compile and run the changes and here's what you should see:

It's kind of anticlimactic to have an entire article devoted to such a simple thing, but bear in mind that we put alot of thought and planning into the previous articles to make the system this versatile and flexible. Not that this is entirely a complicated endeavor but, as mentioned earlier, a little bit of planning goes a long way.
Table of Contents Source Code Article Three Article Five