Wednesday, October 26, 2016

c# - Best way to store game-wide variables


I have an options screen for things like difficulty, resolution, full-screen, etc., but I'm struggling to find the "best" way to store/obtain these variables at run-time.


Currently, I've implemented a Constants class which contains all the GameOption enums, but how do I choose a default for all of these options? Also, how do I get the currently selected enum?


Regarding the resolution, specifically, I've decided to store the values, but I'm unsure of how to get the default, or currently stored, values. Any direction would be great; thanks! :)


namespace V1.test.RPG
{

public class GameOptions
{
public enum Difficulty { EASY, MEDIUM, HARD }
public enum Sound { ON, QUIET, OFF }
public enum Music { ON, QUIET, OFF }
public enum ResolutionWidth
{
SMALL = 1280,
MEDIUM = 1366,
LARGE = 1920,

WIDESCREEN = 2560
}
public enum ResolutionHeight
{
SMALL = 800,
MEDIUM = 768,
LARGE = 1080,
WIDESCREEN = 1080
}
public Boolean fullScreen = false;

}
}

NB: I asked over at SO and they pointed me to this place. There is a comment there but I'd like to hear different ways of doing it / the most used ways.



Answer



Planning to grow:
Hard-coded constants are fine for small projects but, eventually, as your software grows in size, you will wish you could change those settings without having to recompile everything. There are many times you will want to change settings while the game is running and you can't do that with hard-coded constants.


CVars:
Once your project grows, you might want to take a look at CVARs. A CVAR is a "smart variable", so to speak, that you can modify during run-time via a console, terminal, or UI. CVARs are usually implemented in terms of an object that wraps an underlying value. The object can, then, keep track of the value as well as save/load it to/from file. You can store the CVAR objects into a map to access them with a name or other unique identifier.


To illustrate the concept a bit further, the following pseudo-code is a simple example of a CVAR type that wraps an int value:



// just some flags to exemplify:
enum CVarFlags {
CVAR_PERSISTENT, // saved to file once app exits
CVAR_VOLATILE // never saved to file
};

class CVar {
public:
// the constructor registers this variable with the global list of CVars
CVar(string name, int value, int defaultValue, int flags);


int getValue();
void setValue(int v);
void reset(); // reset to the default value

// etcetera...

private:
int flags; // flags like: save-to-file, etc.
int value; // the actual value

int defaultValue; // the default value to reset the variable to
};

// global list of all CVars:
map g_cvars;

Global access:
In the example above, I've assumed that the constructor of CVar always registers the variable with the global cvars map; this is quite useful, since it allows you to declare a variable like so:


CVar my_var = new CVar("my_var", 0, 42, CVAR_PERSISTENT);


That variable is automatically made available in the global map and you can access it from anywhere else by indexing the map with the variable's name:


CVar v = g_cvars.find("my_var");

Persistence:
When the game is shutting down, iterate the map and save all of the variables marked as CVAR_PERSISTENT, to a file. The next time the game starts, reload them.


Case law:
For a more-specific example of a robust CVAR system, check out the implementation featured in Doom 3.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...