• Advertisement
Sign in to follow this  

Flags and such!

This topic is 4169 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've asked a question like this before, and would like to know whats the best way to store flags? At first glance I thought an array of booleans, but then I thought of quest chains and such, so there might be a need to have each flag have anywhere from 2 to 20 values depending on the step the player's on. My next question is, should I use an int or something like that were say... 12345678 represents 8 different flags, 1,2,3,4,5,6,7,8. I think both have their pitfals and advantages. Would the extra memory used to store 8*x amount of shorts vs x amount of ints do something noticeably bad? and would the extra parsing to get each 'digit' take up too many cycles as well?

Share this post


Link to post
Share on other sites
Advertisement
There are a so many ways you could go about this but I'll just list a few.

If you want to have multiple quests in your game with each quest having a series of steps you could try associating each quest with an unique identifier and then have the quests variable filled in with the step the player is on. If you know the total number of quests ahead of time, you could allocate an array of the quests flags on startup, or if you want to be more generic you could just save them in a list allocating them on the fly as the player engages the new quests.

You could use a byte for each but that will limit your values between 0-255. if you plan to have more than 255 quests, you could jump up to a unsigned short (I doubt you'd want a negative quest GUID?).

Example:

struct SQuestInfo
{
byte m_nQuestGUID; // The unique identifier for the quest (between 0-255)
byte m_nCurrentStep; // The step of the quest the player is on (starting at 0)
};

The memory overhead associated with the above struct is only 2 bytes - that's extreamly light. If you wanted to waste your time you could try to squeeze the QuestGUID and the current step into 1 byte, but I doubt you'll want to limit your quest number so small or go through the headache of having to figure out the values when looking at them in the debugger.

If you wanted something easier to read you could also use a string for the quest name. This will take up more memory also, but you don't have to just to a file and lookup the GUID->quest mapping when debugging. Or you could just have a string declared in the struct in debug mode only.

When you save the game just open a file and write the data out to it.

Psudeo Code Example:

// Open file
// Write the number of quests to file
// For each quest
// Write the quest GUID
// Write the qust step

Just remember. Programming as a hobby is all about having fun and learning new things. You've found a great site to come and ask advice.

Share this post


Link to post
Share on other sites
Ah, I'm a bit confused as I have done little work with structs. Would it work somewhat like an array?

That is, for the first value being 0, the 2nd value would be associated with the first value when its 0. so if the 1st value wpuld change, the 2nd value would be different too?

Share this post


Link to post
Share on other sites
Quote:
Original post by Crazyfool
Ah, I'm a bit confused as I have done little work with structs. Would it work somewhat like an array?

That is, for the first value being 0, the 2nd value would be associated with the first value when its 0. so if the 1st value wpuld change, the 2nd value would be different too?


No, think of a struct more as a collection of data types.

For example;

int health, x, y;

as a struct would be:

struct Character{
int health;
int x;
int y;
}

A struct is merely a way of grouping like minded data together. All of the values within a struct are independant of each other. So , using me earlier example, if I did.

myCharacter.health = 42;

myCharacter.y and myCharacter.x would be unaffected.

Share this post


Link to post
Share on other sites
Quote:
Original post by homerj

The memory overhead associated with the above struct is only 2 bytes - that's extreamly light. If you wanted to waste your time you could try to squeeze the QuestGUID and the current step into 1 byte, but I doubt you'll want to limit your quest number so small or go through the headache of having to figure out the values when looking at them in the debugger.



I believe that structure would get padded out to be 4-byte aligned.

As for the OP's question, homerj is absolutely correct that there are a multitude of ways to handle this issue. If you are familiar with bit manipulation I think that is the best option. Essentially you would store a byte or two or however many are necessary to represent all of the quests you would have. So if you have over 255 we obviously would need a short, if we have more quests then we can represent in a short move up to an int, and so on.

Once you've decided on the data type to hold the information you would want to define somewhere a value that correlates to a given quest. So for example you could do

#define FIND_CASTLE_QUEST 1
#define FIND_PRINCESS_QUEST 2

and so on. The player class would then store the "quest", which as stated above is really just being held in a byte. Then we can simply determine which quest they're on by doing

if (players.quest & FIND_CASTLE_QUEST)
..DoStuff();

There is obviously a trade off between memory conservation and code clutter which this method may lead to if not handled properly. Having to do all these if checks to determine the current quests would be overkill and is a task better handled by some sort of quest manager or tracking system, but the representation of the quests could easily remain the same.

Hope that helps :)

Share this post


Link to post
Share on other sites
To answers your origonal question, it really depends. If your looking to store on/off type data, your best off to go with boolean data types. If you are looking to store a value that may have multiple possible values, then you want an enum.

On top of all that, you probrably want to use a struct to store everything.

For example, if you wanted to store information for an RPG for the following things, you could represent it like the following.

** Want to store his current hitpoints, as a value from 1 to whatever **
** Want to store the locations he has visited as a list of bools. For example, there are 200 different locations, where the value could be yes or no **
** Want to store if he is healthy, hurting, or dead **

You would do something like:

enum Health { Healthy, Living, Dead };

struct PlayerStatus
{
int currentHitpoints;
bool locationsVisited[200];
Health current Health;
};

Then, for example, say the visits a certain location, at some point you would have declared an instance of your struct.

PlayerStatus myPlayer;

****

then somewhere in your game, your player vists a location, say a location you gave the value 122 to, you would go
myPlayer.locationsVisited[122] = true;

Then, say a few minutes later, your player gets hit by an orc and loses 5 hitpoints.

myPlayer.currentHitpoints -=5;



Make sense?

Share this post


Link to post
Share on other sites
Wait... when you say "flags" are you talking about boolean flags? When you say 2 to 20 values, do you mean 2 to 20 BOOLEAN values that may be related, or do you mean a single integral "flag" that can hold up to 20 distinct values (as opposed to on or off).

If you mean the former, think about a bitmask. An int, for example, has 32 bits in it (presumably for now), any one of which can be set to 0 or 1. Is this what you are talking about? Or are you talking about an enumeration, where you actually number things?

If you mean the latter, then the other answers seem to be working out.

Share this post


Link to post
Share on other sites
I realized my earlier response may have read your question wrong.

First off. Stop thinking about memory usage. You are talking about such a trivial small amount of data that it isnt even worth optomizing. This isnt exactly the type of thing that you are going to be using in a tight rendering loop that is going to be called thousands of times.


Frankly, I dont know what language you are programming in, but if its either C++, C# or Java, and you want to store a random number of values, your best bet is probrably to use a dictionary or map. These are basically sets of key/value pairs, so you can do something like ( in pseudo code )



myFlags.Add("PlayerJustVomited", true);

then later down the road, when you need to do a test, its the simple syntax:

myFlags["PlayerJustVomited"] which would return the value true.

You really wont beat that for readability of code.

Share this post


Link to post
Share on other sites
I agree with Seraph. Unless you're developing for a console or something else where you have to conserve every byte of memory that you can, I would go for readability over efficiency unless you have good evidence that something is hurting your performance.

Share this post


Link to post
Share on other sites
Oh, and on a similiar note... I planned on storing objects in an array, would it be better to store them in a map, with the filename (Im loading everything from files) as the const char*?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
meanwhile, several more advanced games where there's the need to access lots of global state variables, use so called "property trees" which is basically a std::map with a hierarchical wrapper so that you can pretty much query the map using ldap/filesystem-like "paths" (path=value), such as for example:


//pseudo code:
PropertyTree props
props.setBool("/globals/weather/enable-winds", true);
...

//and later on:
bool flag=props.getBool("/globals/weather/enable-winds");


This was in fact introduced in games/simulators by the open source flight simulator "FlightGear" which used this approach already several years ago, and indeed it has been copied in various other projects, too.

If you are interested in using this, but aren't keen to implement this yourself (or using boost), you may want to check out www.simgear.org where the property tree source code is freely available, the FlightGear developer put it in the public domain, so you can use it in arbitrary projects without licensing restrictions.

If you are interested in an approach with less overhead, you may want to search these forums for "bitwise"/"bitmasks".

Share this post


Link to post
Share on other sites
How would I write a map of an unknown size to a file?

Like, is there an increment method of some sort? For example, I want to be able to store the map info to a file and then be able to read it again later.

Let's say I have "hasPuked" set to 3, and "hasDied" set to 5, I want to be able to store it as..

"hasPuked: 3"
"hasDied: 5" and be able to read it back at launch. Do I need to hardcode all the keys and then just save the associated datas via... how?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Crazyfool
How would I write a map of an unknown size to a file?

Like, is there an increment method of some sort? For example, I want to be able to store the map info to a file and then be able to read it again later.

Let's say I have "hasPuked" set to 3, and "hasDied" set to 5, I want to be able to store it as..

"hasPuked: 3"
"hasDied: 5" and be able to read it back at launch. Do I need to hardcode all the keys and then just save the associated datas via... how?


that's simple serialization-normally, a map such as the aforementioned one would be made up as std::map >, so that you would end up having various (custom) types available, whose serialization you can generically implement using templates for each type that's supposed to be supported:



//PSEUDO Code:
template <class T>
class ValueType {
public:
//overload all required operators (=,==,!=,</> etc)
virtual T getValue(std::map) {}
private:
};


template <class TYPE>
class MyType : ValueType<TYPE> {
public:
//add type specific stuff (this is where you could also add serialization related methods)

private:
TYPE m_myType;
};

if (! find(path) ) newNode(); else assign();

typedef std::map<std::string,ValueType<> > ValueMap

typedef std::map<std::string,MyType<bool> > BoolMap
typedef std::map<std::string,MyType<int> > IntMap
typedef std::map<std::string,MyType<float> > FloatMap
typedef std::map<std::string,MyType<double> > DoubleMap
typedef std::map<std::string,MyType<unsigned> > UnsignedMap

class MyTree {
public:
//add ctors/dtor

void setBool(std::string &path,bool b) {}
void setInt (std::string &path,int i) {}
void setFloat(std::string &path,float f) {}
void setDouble (std::string &path,double d) {}
void setUnsigned(std::string &path,unsigned u) {}

bool getBool(std::string &path) {}
int getInt (std::string &path) {}
float getFloat(std::string &path) {}
double getDouble (std::string &path) {}
unsigned getUnsigned(std::string &path) {}

//add other useful stuff, i.e.:
void serialize() {}
void unserialize(const char* filename) {}

private:
template <class T>
void process(std::string &path,T &val) {if (! find(path) ) newNode(path,val); else assign(path,val);}

template <class T>
void assign(std::string &path, T &val) {}

template <class T>
void newNode(std::string &path, T &val) {m_vmap[path]=val;}

std::vector<ValueMap*> m_vmap;
};



Then you would add direct setters and getters, so that you get the size for each object in order to be able to serialize it to a file-however, you may want to use already existing serialization libraries (i.e. boost) to make your life easier.

Share this post


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

  • Advertisement