// Simple ASCII Console World
// Author: Muhammad Ahmad Tirmazi
// Date: 12 July 2012
// License: BSD 4-Clause
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstdio>
#define _WIN32_WINNT 0x0500
#include <windows.h>
//Standard error macro for reporting API errors
#define PERR(bSuccess, api){if(!(bSuccess)) printf("%s:Error %d from %s \
on line %d\n", __FILE__, GetLastError(), api, __LINE__);}
void cls( HANDLE hConsole )
{
COORD coordScreen = { 0, 0 }; // here's where we'll home the
// cursor
BOOL bSuccess;
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi; // to get buffer info
DWORD dwConSize; // number of character cells in
// the current buffer
//get the number of character cells in the current buffer
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
PERR( bSuccess, "GetConsoleScreenBufferInfo" );
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
//fill the entire screen with blanks
bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
dwConSize, coordScreen, &cCharsWritten );
PERR( bSuccess, "FillConsoleOutputCharacter" );
//get the current text attribute
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
PERR( bSuccess, "ConsoleScreenBufferInfo" );
//now set the buffer's attributes accordingly
bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
dwConSize, coordScreen, &cCharsWritten );
PERR( bSuccess, "FillConsoleOutputAttribute" );
//put the cursor at (0, 0)
bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
PERR( bSuccess, "SetConsoleCursorPosition" );
return;
}
// Our Custom Namespace
namespace pro {
typedef char GameTile; // Just a typedef for 'char'
// Simple Point Class
// Holds the X and Y values of a 2D Object
template< typename T > struct Point
{
Point(void) : X(0), Y(0) {}
Point(T x, T y) : X(x), Y(y) {}
T X;
T Y;
};
// Simple GamePlayer Class
// For controlling the Main Character
struct GamePlayer
{
Point< int > Position;
GameTile Tile;
GamePlayer(std::vector< std::string >& map);
void MoveLeft(std::vector< std::string >& map);
void MoveRight(std::vector< std::string >& map);
void MoveUp(std::vector< std::string >& map);
void MoveDown(std::vector< std::string >& map);
void Draw(void);
};
// Constructor
// Sets the Player's original position
// 1 is the code for a happy face - FIXME!
GamePlayer::GamePlayer(std::vector< std::string >& map)
: Position(2, 2), Tile('*')
{
if (map[Position.X][Position.Y] == ' ')
{
map[Position.X][Position.Y] = Tile;
}
else
{
std::cerr << "Player's Tile is Occupied" << std::endl;
}
}
// Moves the Player 1 Tile To the Left
void GamePlayer::MoveLeft(std::vector< std::string >& map)
{
// If the tile is empty
if (map[Position.Y][Position.X - 1] == ' ')
{
// Remove our player's tile from it's original position
map[Position.Y][Position.X] = ' ';
Position.X --;
// Fill it with our player's tile
map[Position.Y][Position.X] = Tile;
}
}
// Moves the Player 1 Tile To the Right
void GamePlayer::MoveRight(std::vector< std::string >& map)
{
// If the tile is empty
if (map[Position.Y][Position.X + 1] == ' ')
{
// Remove our player's tile from it's original position
map[Position.Y][Position.X] = ' ';
Position.X ++;
// Fill it with our player's tile
map[Position.Y][Position.X] = Tile;
}
}
// Moves the Player 1 Tile Upwards
void GamePlayer::MoveUp(std::vector< std::string >& map)
{
// If the tile is empty
if (map[Position.Y - 1][Position.X] == ' ')
{
// Remove our player's tile from it's original position
map[Position.Y][Position.X] = ' ';
Position.Y --;
// Fill it with our player's tile
map[Position.Y][Position.X] = Tile;
}
}
// Moves the Player 1 Tile Downwards
void GamePlayer::MoveDown(std::vector< std::string >& map)
{
// If the tile is empty
if (map[Position.Y + 1][Position.X] == ' ')
{
// Remove our player's tile from it's original position
map[Position.Y][Position.X] = ' ';
Position.Y ++;
// Fill it with our player's tile
map[Position.Y][Position.X] = Tile;
}
}
} // namespace pro
// A Character Representation
// Of Our Tile Map
static std::string tileMap[] = {
"==========",
"= =",
"= =",
"= =",
"= =",
"= =",
"= =",
"=========="
};
// Not recommended, but works for simple stuff... *
// Calculates the vertical length of the tile map
static int mapLenght = sizeof(tileMap) / sizeof(tileMap[0]);
// Calculates the horizontal width of the tile map
static int mapWidth = tileMap[0].size();
// Vector, to prevent us from dealing with the lousy pointer
// arithmetic that comes with arrays
static std::vector< std::string > tileVector(tileMap, tileMap + mapLenght);
// The player
static pro::GamePlayer player(tileVector);
// Draws the Tile Map
void Draw(void)
{
cls(::GetStdHandle(STD_OUTPUT_HANDLE));
for (int y = 0; y < mapLenght; y++)
{
for (int x = 0; x < mapWidth; x++)
{
std::cout << tileVector[y][x];
}
std::cout << "\n";
}
}
// Gets and Responds to user input
// from the keyboard
bool GetInput(void)
{
if (GetAsyncKeyState(VK_UP))
{
player.MoveUp(tileVector);
}
else if (GetAsyncKeyState(VK_DOWN))
{
player.MoveDown(tileVector);
}
else if (GetAsyncKeyState(VK_LEFT))
{
player.MoveLeft(tileVector);
}
else if (GetAsyncKeyState(VK_RIGHT))
{
player.MoveRight(tileVector);
}
else
{
return false;
}
::Sleep(100);
return true;
}
// Exit when the player presses 'Escape'
bool CheckExit()
{
if (GetAsyncKeyState(VK_ESCAPE))
{
return true;
}
return false;
}
// The main entrypoint function
int main()
{
bool open = true;
Draw();
// The Main Game Loop
while (open)
{
// Redraw if the player's position changes
if (GetInput()) Draw();
if (CheckExit()) open = false;
}
return 0;
}