• Create Account

### #ActualServant of the Lord

Posted 23 June 2013 - 12:46 PM

Here's some untested code I just wrote, illustrating how it might be done.
#include <fstream>
#include <sstream>
#include <algorithm> //For std::replace().

//Loads the entire file, newlines and all, and returns its contents as a string.
//Returns an empty string if the file doesn't exist.
{
//Open the file.
std::ifstream file(filepath.c_str());

//If it failed to open, report the error in whatever way your program handles errors.
if(!file)
{
std::cerr << "LoadFileAsString(): Failed to load '" << filepath << "'\n" << std::endl;
return std::string();
}

//Read the entire filestream into the stringstream.
std::ostringstream stringStream;
stringStream << file.rdbuf();

//Get the string from the stringstream.
return stringStream.str();
}

//If you have C++11 enabled on your compiler, you can use std::stoi() instead of using this function.
int StringToInt(const std::string &str)
{
int value;
std::stringstream stringStream(str);
stringStream >> value;

return value;
}

void TileMap::SetTile(unsigned tileX, unsigned tileY, const sf::Image &tileset, unsigned tilesetLocX, unsigned tilesetLocY)
{
if(tileX < m_MapWidth) return;
if(tileY < m_MapHeight) return;

//Get the subrect for the texture.
sf::Texture texture;
texture.loadFromImage(tileset, sf::IntRect((tileNumX * m_TILESIZE_X), (tileNumY * m_TILESIZE_Y),
m_TILESIZE_X, m_TILESIZE_Y));

//Assign the texture to the tile.
unsigned tileIndex = (tileY * m_MapHeight) + tileX;
m_Map[tileIndex].setTexture(texture);
}

bool TileMap::LoadTileMap(const std::string &filepath, const sf::Image &tileset)
{
if(fileBuffer.empty())
{
std::cerr << "TileMap::LoadTileMap(): Failed to load the map file. Filepath: '" << filepath << "'\n" << std::endl;
return false;
}

//Make sure our tile array is the right size.
m_Map.resize(m_MapWidth * m_MapHeight);

//Push back an extra space for parsing convience, because we are using spaces to mark the end of each pair.
fileBuffer.push_back(' ');

//The left and right sides of pairs.
std::string leftSide, rightSide;

//Which tile we're currently on.
unsigned tileIndex = 0;

//Iterate over the entire string.
bool reachedDivider = true;
for(size_t i = 0; i < fileBuffer.end(); i++)
{
//std::isspace() detects spaces, tabs, newlines, etc... These type of characters are collectively known as 'whitespace'.
if(std::isspace(fileBuffer[i]))
{
//If this is the first whitespace character we've reached since the last pair, then we process the pair.
if(!reachedDivider)
{
//Convert the strings to integers. You can't just cast a char to an int - that only gives you the index of the char in the ASCII chart.
unsigned tilesetLocX = StringToInt(leftSide);
unsigned tilesetLocY = StringToInt(rightSide);

//Convert our tile index to a 2D position. See this link for how to convert from 1D to 2D indices:
//http://www.gamedev.net/topic/627686-2d-tileset-index-to-sub-rectangular-position-calculation/
unsigned tileX = (tileIndex % m_MapWidth);
unsigned tileY = (tileIndex / m_MapWidth);

//Set the tile in the map, with the tileset.
this->SetTile(tileX, tileY, tileset, tilesetLocX, tilesetLocY);

//Move to the next tile.
++tileIndex;

//Reset the string buffers, so we can reuse them for the next pair.
leftSide.clear();
rightSide.clear();
}

//Because we just set 'beginNewPair' to true, even if it was already true, and then
//just continue, we implicitely handle multiple spaces or newlines in a row.
reachedDivider = true;
}
//This is the divider between the left side of the pair, and the right side.
else if(fileBuffer[i] == ',')
{
}
else if(std::isdigit(fileBuffer[i]))
{
//This is the left right side of the pair (the tile row in the tileset).
{
leftSide.push_back(fileBuffer[i]);
}
//This is the right right side of the pair (the tile column in the tileset).
else
{
rightSide.push_back(fileBuffer[i]);
}

//Reset the divider marker, so we're prepared to hit the next divider.
reachedDivider = false;
}
else
{
//Do nothing. Ignores invalid characters.
//The compiler will optimize out this empty 'else {}', it's only here for documentation.
}
}
}

Since I didn't bother compiling it, it might have a mistake or two of its own. If it does, I'll correct it.

### #1Servant of the Lord

Posted 23 June 2013 - 12:45 PM

Here's some untested code I just wrote, illustrating how it might be done.

#include <fstream>
#include <sstream>
#include <algorithm> //For std::replace().

//Loads the entire file, newlines and all, and returns its contents as a string.
//Returns an empty string if the file doesn't exist.
{
//Open the file.
std::ifstream file(filepath.c_str());

//If it failed to open, report the error in whatever way your program handles errors.
if(!file)
{
std::cerr << "LoadFileAsString(): Failed to load '" << filepath << "'\n" << std::endl;
return std::string();
}

//Read the entire filestream into the stringstream.
std::ostringstream stringStream;
stringStream << file.rdbuf();

//Get the string from the stringstream.
return stringStream.str();
}

//If you have C++11 enabled on your compiler, you can use std::stoi() instead of using this function.
int StringToInt(const std::string &str)
{
int value;
std::stringstream stringStream(str);
stringStream >> value;

return value;
}

void TileMap::SetTile(unsigned tileX, unsigned tileY, const sf::Image &tileset, unsigned tilesetLocX, unsigned tilesetLocY)
{
if(tileX < m_MapWidth) return;
if(tileY < m_MapHeight) return;

//Get the subrect for the texture.
sf::Texture texture;
texture.loadFromImage(tileset, sf::IntRect((tileNumX * m_TILESIZE_X), (tileNumY * m_TILESIZE_Y),
m_TILESIZE_X, m_TILESIZE_Y));

//Assign the texture to the tile.
unsigned tileIndex = (tileY * m_MapHeight) + tileX;
m_Map[tileIndex].setTexture(texture);
}

bool TileMap::LoadTileMap(const std::string &filepath, const sf::Image &tileset)
{
if(fileBuffer.empty())
{
std::cerr << "TileMap::LoadTileMap(): Failed to load the map file. Filepath: '" << filepath << "'\n" << std::endl;
return false;
}

//Make sure our tile array is the right size.
m_Map.resize(m_MapWidth * m_MapHeight);

//Push back an extra space for parsing convience, because we are using spaces to mark the end of each pair.
fileBuffer.push_back(' ');

//The left and right sides of pairs.
std::string leftSide, rightSide;

//Which tile we're currently on.
unsigned tileIndex = 0;

//Iterate over the entire string.
bool reachedDivider = true;
for(size_t i = 0; i < fileBuffer.end(); i++)
{
//std::isspace() detects spaces, tabs, newlines, etc... These type of characters are collectively known as 'whitespace'.
if(std::isspace(fileBuffer[i]))
{
//If this is the first whitespace character we've reached since the last pair, then we process the pair.
if(!reachedDivider)
{
//Convert the strings to integers. You can't just cast a char to an int - that only gives you the index of the char in the ASCII chart.
unsigned tilesetLocX = StringToInt(leftSide);
unsigned tilesetLocY = StringToInt(rightSide);

//Convert our tile index to a 2D position. See this link for how to convert from 1D to 2D indices:
//http://www.gamedev.net/topic/627686-2d-tileset-index-to-sub-rectangular-position-calculation/
unsigned tileX = (tileIndex % m_MapWidth);
unsigned tileY = (tileIndex / m_MapWidth);

//Set the tile in the map, with the tileset.
this->SetTile(tileX, tileY, tileset, tilesetLocX, tilesetLocY);

//Move to the next tile.
++tileIndex;

//Reset the string buffers, so we can reuse them for the next pair.
leftSide.clear();
rightSide.clear();
}

//Because we just set 'beginNewPair' to true, even if it was already true, and then
//just continue, we implicitely handle multiple spaces or newlines in a row.
reachedDivider = true;
}
//This is the divider between the left side of the pair, and the right side.
else if(fileBuffer[i] == ',')
{
}
else if(std::isdigit(fileBuffer[i]))
{
//This is the left right side of the pair (the tile row in the tileset).
{
leftSide.push_back(fileBuffer[i]);
}
//This is the right right side of the pair (the tile column in the tileset).
else
{
rightSide.push_back(fileBuffer[i]);
}

//Reset the divider marker, so we're prepared to hit the next divider.
reachedDivider = false;
}
else
{
//Do nothing. Ignores invalid characters.
//The compiler will optimize out this empty 'else {}', it's only here for documentation.
}
}
}


PARTNERS