Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [Solved] Designing questions  (Read 8118 times)

0 Members and 1 Guest are viewing this topic.

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« on: June 13, 2008, 08:21:34 pm »
I'm not sure this fits here, if not please move it.

As my project grows there are functions across multiple files who need access to the renderwindow instance, what is the best way to do this? Have a global instance, or to pass a reference to the instance to each function needing it?...or?

Another thing, I draw a lot of text in my project and right now I only have one sf::String instance where I use the setText-method each time I need to draw a new thing which also means setting a new position, a new center etc. It quickly becomes a lot of setting and getting and I'm wondering if this is an expensive and poor way of doing things?

Creating small projects where everything can be in one file is not hard it's when things get large these designing questions occur especially if you haven't got a lot of experience so any designing tips are welcome.

quasius

  • Full Member
  • ***
  • Posts: 166
    • View Profile
[Solved] Designing questions
« Reply #1 on: June 14, 2008, 01:30:47 am »
Do some research on "singleton design patterns."  That's probably the most straight-forward method.
Basically, it involves creating "manager classes" that only have one instance for the entire life of the program, for example a Renderer class (that could contain the render window.)  The class includes a member that is a static pointer of its own type.  Then you make a static function to get that static self-pointer, which points to the only instance of that class.
So the "renderer" can than be accessed from anywhere in the program.

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« Reply #2 on: June 14, 2008, 01:45:23 pm »
Singletons sound like a good idea. I'm using them in my current project but my knowledge is limited. This is what my design looks like now.

I have a game-class that has a pointer to a state-machine class (designed using a state pattern), this state-machine controlls everything and its states each and everyone has an execute-method where all the game logic (renderwindow etc.) for the specific state is suppose to be (not done yet).

Should I create a render-class and but a pointer to one in the game-class or what is the best way to do this? What should the render-class contain? just the regular singleton stuff (and the renderwindow instance of course  :) )?

The design above might be bad, this is my first larger project.

quasius

  • Full Member
  • ***
  • Posts: 166
    • View Profile
[Solved] Designing questions
« Reply #3 on: June 15, 2008, 06:27:27 pm »
Quote from: "dabo"

Should I create a render-class and but a pointer to one in the game-class or what is the best way to do this? What should the render-class contain? just the regular singleton stuff (and the renderwindow instance of course  :) )?


You could make a single instance of the renderer class in the game-class and make an accessor for it's pointer there.  Or you can use the method I described above and have the renderer include a static pointer to itself.

That method works something like this:  in the header:

Code: [Select]

//SINGLETON STUFF
public:
static Renderer* Instance()
{
if (m_pInstance)
return m_pInstance;

m_pInstance = new Renderer;
return m_pInstance;
}
static void DeleteInstance()
{
if (m_pInstance)
{
delete m_pInstance;
m_pInstance = NULL;
}
}

private:
static Renderer* m_pInstance;
//Default Constructor
Renderer();
//Copy Constructor
Renderer(const Renderer&);
//Assignment Operator
Renderer& operator = (const Renderer&);


The private constructor, copy constructor, and assignment operator prevent making any other instances of the class, which is correct.  Then somewhere in the cpp put:

Code: [Select]

//Initilizes the static instance
Renderer* Renderer::m_pInstance = NULL;


Then you can access it anywhere by including Renderer.h and using Renderer::Instance()->Whatever().
As for what the class includes, well... anything related to rendering your scene, I guess.

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« Reply #4 on: June 15, 2008, 07:22:07 pm »
Thanks a lot for your help.

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« Reply #5 on: June 15, 2008, 08:15:04 pm »
Another thing when you have your project split up in multiple files, where should I put the event-loop? Should it still be in the main()-function even though the states of my state-machine will handle events differently? Or should I have an event loop in the game logics for each state? For example state N might do something if the user presses the ESC-key while state N+1 should not react. Sounds like each state needs its unique event-loop but I might be way off as usually  :)

workmad3

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
[Solved] Designing questions
« Reply #6 on: June 15, 2008, 08:39:15 pm »
Quote from: "quasius"
Do some research on "singleton design patterns."  That's probably the most straight-forward method.
Basically, it involves creating "manager classes" that only have one instance for the entire life of the program, for example a Renderer class (that could contain the render window.)  The class includes a member that is a static pointer of its own type.  Then you make a static function to get that static self-pointer, which points to the only instance of that class.
So the "renderer" can than be accessed from anywhere in the program.


Bzzt... incorrect use of singleton detected :D

Seriously though... a singleton used like this isn't really a singleton, it is a fancy wrapper for a global variable. A correct singleton is a class that you have gone through the design process of your choice for and it has come up as a requirement (note that is requirement, not convenience) that it should only ever have a single instance of it in existence in the program at a time.

Using a singleton as a global variable doesn't avoid the fact it is a global variable with all the usual problems. Honestly, the best thing would be to pass a reference or pointer for your RenderWindow into each function that uses it. It may be a bit of extra typing but the advantages are that you can more clearly see where it is being used (explicit parameters, rather than globals which can be used as implicit parameters), and you don't need to rewrite 90% of your code if you suddenly realise that it would be a good idea to be able to have 2 RenderWindows (which isn't exactly a stretch). Global variables (and singletons masquerading as them) are a good example of the violation of Einstein's idea that 'things should be as simple as they need to be, and no simpler' by being too simple.

For the events, I typically have an event 'dispatcher' that has an event loop and you register components as being interested in certain events with it. The dispatcher then sends out only those events that a component has registered an interest in (for example, in it's current incarnation, I have window events, mouse events, keyboard events and joystick events. If something has no interest in window events, it doesn't register for them and so never needs to handle them). It is called the Observer pattern (and sometimes the publish and subscribe pattern) and is fairly useful for things like event systems :)

quasius

  • Full Member
  • ***
  • Posts: 166
    • View Profile
[Solved] Designing questions
« Reply #7 on: June 15, 2008, 08:49:31 pm »
Quote from: "workmad3"
Quote from: "quasius"
Do some research on "singleton design patterns."  That's probably the most straight-forward method.
Basically, it involves creating "manager classes" that only have one instance for the entire life of the program, for example a Renderer class (that could contain the render window.)  The class includes a member that is a static pointer of its own type.  Then you make a static function to get that static self-pointer, which points to the only instance of that class.
So the "renderer" can than be accessed from anywhere in the program.


Bzzt... incorrect use of singleton detected :D

Seriously though... a singleton used like this isn't really a singleton, it is a fancy wrapper for a global variable. A correct singleton is a class that you have gone through the design process of your choice for and it has come up as a requirement (note that is requirement, not convenience) that it should only ever have a single instance of it in existence in the program at a time.

Using a singleton as a global variable doesn't avoid the fact it is a global variable with all the usual problems. Honestly, the best thing would be to pass a reference or pointer for your RenderWindow into each function that uses it. It may be a bit of extra typing but the advantages are that you can more clearly see where it is being used (explicit parameters, rather than globals which can be used as implicit parameters), and you don't need to rewrite 90% of your code if you suddenly realise that it would be a good idea to be able to have 2 RenderWindows (which isn't exactly a stretch). Global variables (and singletons masquerading as them) are a good example of the violation of Einstein's idea that 'things should be as simple as they need to be, and no simpler' by being too simple.

For the events, I typically have an event 'dispatcher' that has an event loop and you register components as being interested in certain events with it. The dispatcher then sends out only those events that a component has registered an interest in (for example, in it's current incarnation, I have window events, mouse events, keyboard events and joystick events. If something has no interest in window events, it doesn't register for them and so never needs to handle them). It is called the Observer pattern (and sometimes the publish and subscribe pattern) and is fairly useful for things like event systems :)


Yes there are other ways to do it.  I gave a simple straight-forward one.  He asked for the proper way to do what he was already trying to do, which I gave.  And singleton is a perfectly viable design pattern that is used in professional projects.  Creating a dispatcher system is far more complicated than singletons and almost certainly a bad idea for his first app-design problem.  Also, singleton is probably the fastest (execution speed) design pattern.  Passing pointers and references around everywhere isn't just "extra typing."  It's extra execution time too.

Edit:  There is no reasonable case I can think of where you would want more than one renderer class.  If you want multiple render-targets, that would involve reworking the render functions in the render function not "rewriting 90% of the code."

Edit Edit:  I'm not saying your info is bad, I'm saying it's probably way more solution than the OP is looking for or needs.

quasius

  • Full Member
  • ***
  • Posts: 166
    • View Profile
[Solved] Designing questions
« Reply #8 on: June 15, 2008, 08:59:39 pm »
Quote from: "dabo"
Another thing when you have your project split up in multiple files, where should I put the event-loop? Should it still be in the main()-function even though the states of my state-machine will handle events differently? Or should I have an event loop in the game logics for each state? For example state N might do something if the user presses the ESC-key while state N+1 should not react. Sounds like each state needs its unique event-loop but I might be way off as usually  :)


The "main loop" will often be in your main class/function.  Although it should be lean.  Something like:

{
pInputHandler->HandleInput();
pStateMachine->Update();
pRenderer->Render();
}

Basically, you are just tapping all your major systems from within the main loop.  If your main loop function starts getting complicated and ugly, you should probably move some stuff to another class.  The main class should contain minimal-to-no functionality in itself.

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« Reply #9 on: June 15, 2008, 09:01:13 pm »
Quote from: "workmad3"

For the events, I typically have an event 'dispatcher' that has an event loop and you register components as being interested in certain events with it. The dispatcher then sends out only those events that a component has registered an interest in (for example, in it's current incarnation, I have window events, mouse events, keyboard events and joystick events. If something has no interest in window events, it doesn't register for them and so never needs to handle them). It is called the Observer pattern (and sometimes the publish and subscribe pattern) and is fairly useful for things like event systems :)


I'm gonna try to find some more info about this, sounds interesting and probably too complicated for me  :)

workmad3

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
[Solved] Designing questions
« Reply #10 on: June 15, 2008, 11:23:29 pm »
Quote from: "quasius"
Yes there are other ways to do it.  I gave a simple straight-forward one.  He asked for the proper way to do what he was already trying to do, which I gave.  And singleton is a perfectly viable design pattern that is used in professional projects.  Creating a dispatcher system is far more complicated than singletons and almost certainly a bad idea for his first app-design problem.  Also, singleton is probably the fastest (execution speed) design pattern.  Passing pointers and references around everywhere isn't just "extra typing."  It's extra execution time too.


I never said singleton wasn't viable. I said that using a singleton as a 'design pattern' stand-in for a global variable wasn't correct usage. I know that singletons are used in professional projects, and I personally think that about half of them are probably just to have global variables without someone saying that global variables are bad.

Talking about execution speeds of design patterns seems a bit away from the point though. Singletons can be very fast... so can smart pointers (another design pattern) facades, or any other design pattern. They can also all be slowed down considerably because of other design constraints (such as singletons checking access rights, or performing lazy creation of expensive objects, or smart pointers doing all sorts of fancy stuff). It all depends on the design :) And a singleton requires an extra function call. An extra parameter requires one extra parameter added onto a function call that is already being made. An extra function call is frequently more expensive than an extra parameter to an existing call (especially if your singleton uses lazy creation and is less likely to be inlined because of it, or you can't inline it because you are using a singleton to an abstract interface and don't want to expose what you are actually creating).

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« Reply #11 on: June 16, 2008, 02:51:10 pm »
I have read a little about the observer pattern and I think I know what it is used for now. But I don't know how it would be implemented in my current game design. Should each state of the state-machine have an event-stack where all the interesting events get sent too?  :?

If I have understood the observer pattern correctly every observer gets a notification when something they are interested in happens, but in my case only the active state of my state-machine needs this notification even if more states are interested in for example key-inputs.

Any help are deeply appreciated.

workmad3

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
[Solved] Designing questions
« Reply #12 on: June 16, 2008, 05:03:10 pm »
It depends on the observer pattern... with a state machine like that, I think I'd personally set things up so that there is a second 'interface' between the event publisher and the states that keeps track of the active state. It receives all events and queries the active state as to wether or not it wants a particular event and forwards it on.

The other solutions would be for your state manager to deregister the old state and register the new state for events when they get switched, or to have an event publisher that only has one observer at a time (which is a valid design, and the easiest to implement :)).

As for the actual implementation of the publisher... decide upon an interface for your observers, then have a class that implements your event loop and accepts pointers or references to observers in register and deregister events. You then store these internally and (if they are set) call the interface methods on them when the correct events occur. It doesn't take too much code to do, although if you start making it complicated you can require a fair amount of code to track things like stray events.

dabo

  • Sr. Member
  • ****
  • Posts: 260
    • View Profile
    • http://www.dabostudios.net
[Solved] Designing questions
« Reply #13 on: June 16, 2008, 05:55:29 pm »
Thanks again, interesting and good ideas but I think I'm in over my head. But I'm gonna read what you have written a couple of times more and mayby I can put something together  :)

I think this is very interesting area but I wish my knowledge wasn't so limited  :)

workmad3

  • Jr. Member
  • **
  • Posts: 71
    • View Profile
[Solved] Designing questions
« Reply #14 on: June 16, 2008, 06:17:52 pm »
When I get home, I could send you the current state of my event dispatcher if you wanted :) I've created it so that the standard dispatcher just has one listener and then created adapter listeners that can have multiple listeners on them (and they forward the events to each one). It works, and is pretty much complete but I'm not entirely happy with how my event structure works in it though :) It's still good enough to show how the idea works, and probably easy enough to use anyway :)