• Advertisement
Sign in to follow this  

File Input and Array defining

This topic is 4247 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a class for a map and I'm having a problem getting my map loaded from text, and stored in an array. The way I'm trying to do it is like this.
//in Map.h
class Map
{
    private:
        char MapFileLines[100][100];
        char FileLineBuffer[100];
        TextureManager TexMan;
        bool LoadMap();
    public:
        Tile MapArray[100][100];
        Map();
};
//in Map.cpp
bool Map::LoadMap()
{
    int line = 0;
    std::ifstream MapFile("Map.txt");
    if(!MapFile.is_open())
    {
        return false;
    }
    while(!MapFile.eof())
    {
        std::cin.getline(MapFile, FileLineBuffer);;
        MapFileLines[line] = FileLineBuffer;
        line++;
    }
    MapFile.close();
    return true;
}
Map::Map()
{
    if(!LoadMap())
        MessageBox(NULL, "The map was not loaded", "RPG", MB_ICONEXCLAMATION);
    for(int yIndex = 0; yIndex < 100; yIndex++)
    {
        for(int xIndex = 0; xIndex < 100; xIndex++)
        {
            MapArray[yIndex][xIndex].ID = MapFileLines[yIndex][xIndex];
            MapArray[yIndex][xIndex].XPos = xIndex;
            MapArray[yIndex][xIndex].YPos = yIndex;
            MapArray[yIndex][xIndex].CopyTextureTile(TexMan.GetTexture(MapArray[yIndex][xIndex].ID));
        }
    }
}

Am I trying to do this right? I had it with vectors but doing a 2d vector just made it harder. I am trying to get a whole line out of the file, but it doesn't want to use getline. Could someone help me with this?

Share this post


Link to post
Share on other sites
Advertisement
std::cin.getline(MapFile, FileLineBuffer);; is wrong. It should be

MapFile.getline(FileLineBuffer, sizeof(FileLineBuffer));

or something like that. There is also a non-member std::getline function that may work.

Share this post


Link to post
Share on other sites
Aha, that worked but now it forbids the assignment of arrays on line 16.

Share this post


Link to post
Share on other sites
There. I fixed it with this

bool Map::LoadMap()
{
int line = 0;
std::ifstream MapFile("Map.txt");
if(!MapFile.is_open())
{
return false;
}
while(!MapFile.eof())
{
MapFile.getline(FileLineBuffer, sizeof(FileLineBuffer));
for(int iter=0; iter<100; iter++)
{
MapFileLines[line][iter] = FileLineBuffer[iter];
}
line++;
}
MapFile.close();
return true;
}




Thank you!

Share this post


Link to post
Share on other sites
There is also an std::string version of getline that works with string buffers. For this one you don't need to pass in the buffer size:

std::ifstream MapFile("Map.txt");
std::string FileLineBuffer;
std::getline(MapFile, FileLineBuffer);

Share this post


Link to post
Share on other sites

/in Map.h
class Map
{
private:
typedef std::vector<std::string> StringArray;
TextureManager TexMan;
// just pass the result to the method - no need for member data
// that'll only be used once (also const now, since no member data
// is manipulated)
bool LoadMap( StringArray & ) const;
public:
typedef std::vector<Tile> TileArray;
typedef std::vector<TileArray> MapType;
MapType MapArray;
Map();
};
//in Map.cpp
bool Map::LoadMap( StringArray & mapLines )
{
mapLines.clear();
std::ifstream MapFile("Map.txt");
if(!MapFile.is_open())
{
return false;
}
while(!MapFile.eof())
{
std::string line;
std::getline(MapFile, line);
mapLines.push_back( line );
}
MapFile.close();
return true;
}
Map::Map()
{
StringArray mapLines;
if(!LoadMap( mapLines ))
MessageBox(NULL, "The map was not loaded", "RPG", MB_ICONEXCLAMATION);
else {
size_t const maxX = mapLines[0].length();
// allocate rows
MapArray.resize( mapLines.size() );
for(size_t yIndex = 0; yIndex < mapLines.size(); ++yIndex)
{
// make sure the line width matches accross the file
if ( MapArray[yIndex].length() != maxX ) {
// invalidate the map
TexMan.ClearTextures();
MapArray.clear();
MessageBox(
NULL, "The map was not loaded - broken data file.", "RPG", MB_ICONEXCLAMATION
);
break;
}
// allocate tiles for this row
MapArray[yIndex].resize( maxX );
// load tiles
for(size_t xIndex = 0; xIndex < maxX; ++xIndex)
{
MapArray[yIndex][xIndex].ID = mapLines[yIndex][xIndex];
MapArray[yIndex][xIndex].XPos = xIndex;
MapArray[yIndex][xIndex].YPos = yIndex;
MapArray[yIndex][xIndex].CopyTextureTile
(
TexMan.GetTexture( MapArray[yIndex][xIndex].ID )
);
}
}
}
}


Share this post


Link to post
Share on other sites
I'm assuming you mean this line:

MapFileLines[line] = FileLineBuffer;

Although it's not line 16 at all in the code you posted.

The value of an array in C and C++ is a pointer. You can't assigne a pointer to an array, unfortunately. You can get around this by assigning a struct that contains an array, or just use std::copy() -- even the basic memcpy() will do the trick for plain data types.


memcpy(MapFileLines[line], FileLineBuffer, sizeof(MapFileLines[line]));

Share this post


Link to post
Share on other sites
There is also an std::string version of getline that works with string buffers. For this one you don't need to pass in the buffer size:

std::ifstream MapFile("Map.txt");
std::string FileLineBuffer;
std::getline(MapFile, FileLineBuffer);

Share this post


Link to post
Share on other sites
Ok ok ok.

0) Arrays are strange things in C++. In many senses, they... aren't things. You can't just assign one to another.

1) DaRookie has the right ideas. Using these tools, you get to do all the kinds of assignments you would expect to be able to, and not have to hard-code the sizes. Incidentally, the code also shows how to use the free-function std::getline() that works with std::strings.

2) There are probably some problems with your design if tiles "know where they are in the map". Why do you think you need this cross-linking?

3) Why do you want to keep the read-in file data as a private member? I really, really think you want it as a local variable in the loading function, instead.

4) If the loading fails, you should throw an exception from the constructor instead, and let the calling code put up the message box.

5) Why not have a constructor for Tiles that sets the ID and grabs the associated texture? Also, why is there a TexMan (texture manager) object? Will there be more than one of them created? If not, do you really feel you are gaining anything by wrapping the "texture management" functions into an object of which only one would be instantiated?

Share this post


Link to post
Share on other sites
The reason I made a Texture Manager, was because It's going to be used for stuff besides the Tile Map. I am going to use the same bmp loading techniques for Character Sprites, Battle Animation Frames, Inventory Items, and So on. I will have GLuint arrays set up for each of these things.

Share this post


Link to post
Share on other sites
Ahhhh, now I'm all confused. When I started working on it I changed my char* to strings, but I don't want strings I want singular spots in an array. Since my map is full of numbers would it be good to input an array of integers rather than chars?

Share this post


Link to post
Share on other sites
Quote:
Original post by Niddles
Ahhhh, now I'm all confused. When I started working on it I changed my char* to strings, but I don't want strings I want singular spots in an array. Since my map is full of numbers would it be good to input an array of integers rather than chars?


The only difference between int and char is that int is usually 32-bit and char is 8-bit. They are both just numbers. If your values ever get bigger than 255 (MAX_CHAR) you should probably switch to int.

EDIT: You are right, you don't want strings, you want a two dimensional array of numbers. The other poster, darookie probably got too carried away with changing char* to std::string :-)

[Edited by - deathkrush on July 7, 2006 12:03:49 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement