• 15
• 15
• 11
• 9
• 10

Just a few general questions

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

Recommended Posts

Hello everyone, just had a few general questions [C++] and I wanted to get some opinions from those who've had more experience in the subject than I.

First off, I was wondering how you guys tend to manage globals? Like for instance, in my current scene graph set up, I would need each transformation node to be able to access the same matrix stack, as well as possibly passing down the renderer, sound manager, GUI manager, etc. I'm wondering if I should perhaps group all the global objects into one big one and pass that around, or pass each pointer around, or should I use singletons/globals? Or perhaps there's some way that doesn't make everything complicated? I'd love to hear some thoughts on the matter.

Second question I had that I've been trying to figure out an elegant solution to for a while now is dealing with settings in a transparent way. I usually just have one global pointer to a struct with all the settings and call a function to save and load them but that's difficult to expand and is far from clean. Would anyone happen to have a better way of handling options?

I have been considering perhaps parsing an XML file for groups of settings and having different implementations of my interfaces read the settings as appropriate through callbacks but I'm not sure that'd really be worth the effort for something so simple.

Sorry if my post is poorly worded, I've had a stressful evening. Thanks for readin'.

Edit: On a fourth read through I figured the comment about what I was considering may be a bit vague. Perhaps some sample pseudocode to demonstrate:
//Each module that wants a certain section of options would implement something like this:class ClsOptionsGraphics : public IOptions{public:	std::string GetSectionName();	//Returns the section in the options file that applies to this object	bool Parse(XMLNode* Node);	//The parent XML node that matches [if any] is passed to this, otherwise default settings are used//etc};

Somethin like that.

Share on other sites
Quote:
 Original post by MushroomSambaHello everyone, just had a few general questions and I wanted to get some opinions from those who've had more experience in the subject than I.First off, I was wondering how you guys tend to manage globals? Like for instance, in my current scene graph set up, I would need each transformation node to be able to access the same matrix stack, as well as possibly passing down the renderer, sound manager, GUI manager, etc. I'm wondering if I should perhaps group all the global objects into one big one and pass that around, or pass each pointer around, or should I use singletons/globals? Or perhaps there's some way that doesn't make everything complicated? I'd love to hear some thoughts on the matter.

My personal opinion is that singletons really suck. Maybe there is some rare use for them, but I don't think this case is one of those.
I simply grouped that stuff into a class called engine that exposes systems similar to the ones you named. However I hardly every pass the engine around: I only need one or 2 systems at a time and then I simply pass around those systems instead. Maybe this would be an option for you.

Quote:
 Second question I had that I've been trying to figure out an elegant solution to for a while now is dealing with settings in a transparent way. I usually just have one global pointer to a struct with all the settings and call a function to save and load them but that's difficult to expand and is far from clean. Would anyone happen to have a better way of handling options?

I use a service provider for stuff like that. It acts as a storage for services and allows you to retrieve them: serviceProvider.service<RequiredService>(). A service can be anything (for example a scheduler based on a thread pool to execute tasks asynchronously, a logger, etc...). One service is handling all my settings. However I didn't need to use another abstraction, since I'm using QSettings which allows me to store/retrieve settings to/from different sources (registry, files, etc...).
This service can then load settings upon construction and store them upon destruction (or when the appropriate function is called manually).

You might be interested in boost::property_tree when it comes to actually storing / retrieving settings.

*edit*
I also think you should really separate reading settings and the actual interface to access them during your game:
class ClsOptionsGraphics{public:    ClsOptionsGraphics(const boost::property_tree::ptree& tree)        : m_tree(tree.get_child("graphics"))    {}    int maximumMeshes()    { return m_options.get<int>("maximumMeshes"); }    float maximumViewDistance()    { return m_options.get<float>("maximumViewDistance"); }private:   boost::property_tree::ptree   m_tree;}

Creating the property_tree in the first place should be done somewhere else (probably during startup).

Share on other sites
Why does every node in your scenegraph need to access the same matrix stack? The beauty of the scenegraph concept is that it is a recursively defined data structure. That means that you can do things like this:

Matrix SceneGraphNode::GetFinalTransformation(){   if(ParentNode)      return ParentNode->GetFinalTransformation().Compose(LocalTransformation);   return LocalTransformation;}void SceneGraphNode::TraverseForSomeReason(const Matrix& transformation){   // Do something useful   Matrix composedtransform(transformation.Compose(LocalTransformation));   for(ChildContainer::iterator iter = Children.begin(); iter != Children.end(); ++iter)      (*iter)->TraverseForSomeReason(composedtransform);   // Maybe post-recursion do something else useful}

In a similar vein, why should your scenegraph ever need to access your renderer, or sound manager, or GUI system? Everything is much cleaner if you use a layer between the scenegraph and other systems. For instance, rendering can be handled by passing a single "render request queue" object into your scenegraph node's Render() function. Recursively traverse the scenegraph and add a request for every render action into the queue. Once you're done, you can pass that queue off to the render manager, which will actually take care of doing the drawing and such. Voila - loose coupling [smile]

Lastly, as for settings: my standard solution is pretty simple. I have a std::map<std::string, std::string> that is parsed out of the raw config file (with stock wrappers for INI-like formats, XML-like formats, and whatnot). This blob is wrapped by a simple template interface that lets you retrieve a given named parameter's string data as a particular type, say via ConfigData.ReadEntry<float>("volume"). With a tiny bit of work you can use this for non-primitive and even non-POD entry types - all you have to do is ensure that they can sanely construct themselves from whatever string was in the raw config file.

Once that infrastructure is set up, you simply construct various systems by handing off the configuration data of choice:

int main(){   ConfigData config("foo.xml");   Renderer renderer(config);      GameLogic game(config);   game.GameLoop(renderer);}

Obviously you can get more sophisticated with this if you want things like settings profiles, per-user options, etc. etc. but the core framework is so easy to extend that IMO it's a good place to start for just about any requirements.

Share on other sites
Quote:
 My personal opinion is that singletons really suck.

Agreed. I keep hearing people say globals are evil and such, but used correctly they're fine IMO.

Quote:
 I simply grouped that stuff into a class called engine that exposes systems similar to the ones you named.

This is the way I was planning on doing it, just wasn't sure if there was a more elegant way of achieving the same result.

As for that QSettings thing, I'ma have to check that one out.

Quote:
 Why does every node in your scenegraph need to access the same matrix stack?

That was just an example, though I would prefer to have a single pointer to the current matrix if another system needed it or somethin. Nothin wrong with having it handy, right? :D

I do get where you're coming from though, passing things through recursively would probably make things easier than having a global object.

Both answers were very informative, I appreciate the feedback, and at least have some direction to take the problems in.

Share on other sites
Quote:
 Original post by MushroomSambaThat was just an example, though I would prefer to have a single pointer to the current matrix if another system needed it or somethin. Nothin wrong with having it handy, right? :D

Yes, there's something wrong with that.

First of all, you aren't going to need it. Just because it seems like it may come in handy at some point in future doesn't mean it's justified. The more code you write for this kind of reason, the more likely you are to end up maintaining a lot of half-used concepts and excess baggage. If you never write code you don't need, that code can't cost you time, bugs, incorrect documentation, or any other pitfalls down the road.

Secondly, and more generally, you should try to follow the Law of Demeter. Making things accessible just because you might want to touch them from some other system is a very bad design habit; it leads to deeply interconnected code where you should be building independent systems. (This is the motivation behind the common idea that globals and singletons are bad.) If your game needs to access scenegraph transformation matrices in a way that doesn't fit into the two paradigms I demonstrated earlier, you're doing something wrong.