Jump to content
  • Advertisement
Sign in to follow this  
squizm

Help with Class Serialization

This topic is 2607 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

Hello,

I'm working on a port of a free Print'n'Play game from BoardGameGeek called ZombiePlague. Its my first full game project so be easy on me. I'm having trouble saving a vector or a class and reading it back. To begin, here is the class I'm looking to write to a file:



enum Facing{
NORTH = 0,
EAST = 1,
SOUTH = 2,
WEST = 3
};

enum GamePieceType{
CHARACTER = 0x01,
ZOMBIE = 0x02,
BARACADE = 0x04
};


class GamePiece
{
public:
int tileX;
int tileY;
int facing;
int actionPoints;
unsigned char _type;
GamePiece() {facing = NORTH; actionPoints = 2; _type = ZOMBIE;};
GamePiece(int x, int y, int direction, int ap, unsigned char type) {tileX = x; tileY = y; facing = direction; actionPoints = ap; _type = type;};
};



In my game, I keep the game pieces in an array as that there could be more pieces added every turn. What would be the best method to write this vector to a file and read it back? I've had multiple attempts and none have been successful. Any web reference or feedback appreciated.

Here is what I've tried without success:


void loadLevel()
{
fstream levelData ("level.dat", ios::in | ios::binary);
for(int i = 0; i < (int)gamePieces.size(); i++)
levelData.read((char *)&gamePieces.at(i), sizeof(GamePiece));
};

void saveLevel()
{
fstream levelData("level.dat", ios::out | ios::binary);
for(int i = 0; i < (int)gamePieces.size(); i++)
levelData.write((char *)gamePieces.at(i), sizeof(GamePiece));
};



Here is a pic of the prototype I have so far: LFUSX.png

Share this post


Link to post
Share on other sites
Advertisement
Oh edit: You wanted information on serialization this is not serialized for different platforms.

Might I suggest a few things

1) You probably want to start adding a header to the file that specifies the number of elements to be read.

My map header looks like this:
struct MapHeader
{
int MapLoadVersion;
int NumberOfTiles;
int MapSizeX;
int MapSizeY;
int CheckSum;
};


2) My tile class has no member functions just variables
like so:

class MapTile
{
public:
int x;
int y;
int Layer;
int iCurrentTileGraphic; //Tile in this location
int iOriginalTileGraphic; //this was the tile we started with (for animation)
int Lighting; //Lighting value associated with this tile
int Alpha; //Transparency value
bool Blocked; //If this tile is blocked or not
int AnimNum;
int AnimSpeed;
};


3) Building up a checksum you can store when you save and load is really nice so that you can verify that what your reading is actually correct since the last time it was saved.
I end up using the X+Y+TILENUM for every single tile and adding them and using that for the checksum.

And when I load the file for each element I just do
MapTile temp;
inbal.read(reinterpret_cast<char *> (& (temp)), sizeof(MapTile));

Then pushback temp to my vector again.

Share this post


Link to post
Share on other sites
I have two suggestions. One is to add a header to you file as suggested before. A header will allow you to have maps of different sizes and gives you freedom in other ways

Another suggestion I have is the move the saving and loading code of a GamePiece into a the GamePiece class.

So something like this.



class GamePiece
{
public:
int tileX;
int tileY;
int facing;
int actionPoints;
unsigned char _type;

// save and load functions go inside the class
void readFromStream(fstream& stream);
void writeToStream(fstream& stream);

GamePiece() {facing = NORTH; actionPoints = 2; _type = ZOMBIE;};
GamePiece(int x, int y, int direction, int ap, unsigned char type) {tileX = x; tileY = y; facing = direction; actionPoints = ap; _type = type;};
};


Then in your cpp file


void GamePiece::readFromStream(fstream& stream)
{
stream.read((char *)&this, sizeof(GamePiece));
}

void GamePiece::writeToStream(fstream& stream)
{
stream.write((char *)&this, sizeof(GamePiece));
}


The reason it is a good idea to have the GamePiece load and save itself is that other objects shouldn't have to know how GamePiece is implemented to use it. This way, the correct way to read and write the object is in one place and other objects don't have to know how to read and write the object. All it does is call a single method to do that.

You read and write code would then look something like this

void loadLevel()
{
fstream levelData ("level.dat", ios::in | ios::binary);

//TODO
// load information about the map, the number of tiles, the width and height, yewbies post describes this well

for(int i = 0; i < (int)gamePieces.size(); i++)
gamePieces.readFromStream(levelData);
}

void saveLevel()
{
fstream levelData("level.dat", ios::out | ios::binary);

//TODO
// save the information about the map

for(int i = 0; i < (int)gamePieces.size(); i++)
gamePieces.writeToStream(levelData);
}


Those are my two bits

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!