#Off topic When I was logging in, I have noticed 600,00x members registered on this forum. Congrats on the 600k!
Yes, new members register at an astonishing rate here . . . when I logged in there were six less members than there are now.
Hello.
My console game is going pretty well, even though I don’t have much spare time to expand it. I have some ideas I would like to add, but I'm not sure how to accomplish them.
First of all, I would like to save data. Most of my data is encapsulated in classes, so I could pass a pointer of all my classes to a function, make it write the data to a file, and then use a similar function to load it. However, I guess writing the data like that would make it very messy, and adding extra content would mean completely rewriting the save\load functions. Also, some of my classes are inherited from other classes, and I have used some aggregation, which makes saving a bit more complex...
[Sorry if this is a bit advanced. I assume you're a pretty good programmer from that description, but still, I do get carried away sometimes.]
Here's one way you could go about it that I can think of; it's a reasonably clean way. Have each class write itself out. This is a nicely object-oriented solution, and it means that adding new content isn't too laborious. If all of your classes are derived from some base class, for example, you could have a function like
virtual void write(std::ostream &stream) = 0;
which would write the data to a stream. You probably have one or a few top-level classes, so to save the game you'd just call write() on those classes, which would in turn propogate down and call write() on the other methods. Just as a quick example:
class NPC : public GameObject {
private:
std::string name;
Inventory *inventory;
Disposition *disposition;
// ...
public:
virtual void write(std::ostream &stream);
};
void NPC::write(std::ostream &stream) {
stream << "[class NPC]\n";
stream << name << std::endl;
inventory->write(stream);
disposition->write(stream);
}
You can see how each class only has to write out the data it is responsible for. It makes for a nice design. Sorry if you don't understand virtual functions and stuff that I've used here . . . you can ignore it, or better yet look up what it is.
The trouble comes when you're trying to read stuff in, especially if you've used inheritance extensively. You basically need a way to decide which class to construct when you see something like "NPC" in the file. A few ways to do this:
- Maintain a list of function pointers, in a std::map, say, mapping from std::strings like "NPC" to functions which know how to construct an NPC object. Or if maps are too advanced, think of a giant if-else or switch statement.
This isn't too bad of a solution, but it's not very object-oriented.
- You could also implement a virtual constructor system. (This is a nice reference for this type of thing: http://www.informit.com/guides/conte...lus&seqNum=184) You could, at the beginning, construct some empty objects and register them in a std::map (yes, I like maps). Then just call a construct() method on that object . . . perhaps an example will make things clear.
Here's the example I promised.
#include <iostream>
#include <map>
#include <string>
class Base {
public:
/** Obligatory virtual destructor. */
virtual ~Base() {}
virtual void deal_with_things() = 0;
virtual Base *construct() = 0;
};
class One : public Base {
public:
virtual void deal_with_things() { std::cout << "I'm a One.\n"; }
virtual One *construct() { return new One(); }
};
class Two : public Base {
public:
virtual void deal_with_things() { std::cout << "I'm a Two.\n"; }
virtual Two *construct() { return new Two(); }
};
int main() {
std::map<std::string, Base *> name_map;
name_map["One"] = new One();
name_map["Two"] = new Two();
// Let's pretend this came from a file somewhere.
const std::string construct = "One";
Base *object = name_map[construct]->construct();
object->deal_with_things();
return 0;
} Anyway, hopefully that will give you some interesting ideas . . . .
So, if you have any ideas on how to save all my data and then load it up without having to worry about future content, I would like to hear them. I was thinking, writing to something like an .ini file, and separating the data with sections. I'm not sure how it would work though.
My second idea was to add easy to edit modules. So that other users could create content, send it to me, and I would link the modules to my game. The reason I just don't create some easy to inherit classes and editable headers, is because not all players would have a compiler and knowledge of C++, so I was thinking of something like .lua files. I'm not sure how that works either. Technically it could be something like this:
My user defined template, saved to a text file:
Data 1:
Data 2:
Data 3:
.... etc.
The user would edit each "Data" segment, then I link it to the game, a function converts the module to an inherited class, where "Data" are the necessary parameters, such as dialogues or stats.
Any ideas are greatly welcomed!
If you want your program to have Lua scripts, it's far from trivial. You have to have some sort of interpreter for the scripting language; you could write your own (quite difficult, though less so if you use bison and flex) or use an existing Lua scripting library. I hear they exist. I've never tried it myself.
It really depends on your game, but I'd consider implementing something like I described above. If you want the structure of your file to be, e.g.
name: long_hall
description: You are standing in a long hallway.
east: shadowed_room
west: dead_end
name: shadowed_room
...
then you could just create a class which "reads" itself in the manner described above. If you want more complicated structures like
message += "Before you stands the messenger."
if(has_seen_message) {
message += "'Well, what are you waiting for?'"
}
else {
message += "'Sir! The <insert suitably medieval name here> are attacking!'";
has_seen_message = 1;
}
then you're in for a lot of code.

It's quite complicated to process that sort of thing. I'd probably implement a C++ interface, just so that you can make sure it works and write some basic modules yourself, and then write an interpreter that uses the C++ interface. You can write a simple interpreter and make it more complicated from there.
But I'm rambling now. Have fun with your coding.