Game Design Help

Started by
19 comments, last by ChaosX2 18 years, 3 months ago
The decision whether to use a monostate or a singleton depends on the problem domain.
You can find a detailed comparison of both here.

HTH,
Pat.
Advertisement
I've decided to go with a singleton at this point. I'm pretty weak on C++ templates and I'm having a problem getting the code you posted to work with my current method of registering the callbacks in a Vector. Could you post some example code on how to get the callback template to work with a vector?
<a href="http://ruggles.hopto.org>My Personal Website
Ok well I'm at a loss even how to use the code you posted in my current class. Can anyone help?
<a href="http://ruggles.hopto.org>My Personal Website
Changes in the header:
class WindowManager{private:   ...   // pointers or references must be used, since polymorphism is at work here   typedef std::pair<int, ResizeCallback *> ResizeCall;   typedef std::vector<ResizeCall>          CallbackVector;   // the vector now holds a pair of <id, Functor>   CallbackVector                           resizeVector;   // find by id functor   struct HasId {       // ctor.       HasId( int id ) : id( id ) { }       int id;       // function operator, allows a call like "HasId hasId(x); hasId( call );"       bool operator( )( ResizeCall const & call ) const { return call.first == id; }   };   ...};

Changes in the implementation:
// delete pointers hereWindowManager::~WindowManager(){	glfwTerminate();        for ( size_t i = 0; i < resizeVector.size(); ++i )             delete resizeVector.second;	resizeVector.clear();}// note that the windowmanager takes ownership of the pointer and that// the resize functor must be created using "new"int WindowManager::registerResizeFunction(ResizeCallback * resizeFunctor){	ResizeCall newResizeCall;	static id = 0;	id++;	newResizeCall.first = id;	newResizeCall.second = resizeFunctor;	resizeVector.push_back(newResizeCall);	return id;}// find the documentation for "remove_if" in your STL docsvoid WindowManager::unregisterResizeFunction(int id){        // find the callback and remove it by moving it to the end	CallbackVector::iterator iter = std::remove_if( resizeVector.begin( ),           resizeVector.end( ), HasId( id ) );        // erase it (there can only be one)        delete iter->second;        resizeVector.erase( iter );}void GLFWCALL WindowManager::windowResize(int width, int height){	CallbackVector::const_iterator iter;	wm_width = width;	wm_height = height;	// Call functions in the vector	for (iter = resizeVector.begin(); iter != resizeVector.end(); ++iter)	{		iter->second.OnResize(width, height);	}}

Sample usage with "free functions":
struct MyResizeFunctor : public ResizeCallback {    void OnResize( int width, int height ) {         // do something    }};...WindowManager::getInstance()->registerResizeFunction( new MyResizeFunctor );

Sample usage with class members:
class MyClass {   ...   void Resized( int, int ) { ... }   int resized;public:      MyClass( ) {       // register with the window manager        resized = WindowManager::getInstance()->registerResizeFunction( new ResizeMemberCallback( this, Resized ) );       // if the above doesn't compile for some reason://       resized = WindowManager::getInstance()->registerResizeFunction( new ResizeMemberCallback<MyClass>( this, Resized ) );   }   ~MyClass( ) {       // unregister       WindowManager::getInstance()->unregisterResizeFunction( resized );   }};


HTH,
Pat.
Thanks, that helps a lot.
<a href="http://ruggles.hopto.org>My Personal Website
The code you posted doesn't seem to compile. Here are the errors I'm getting

error C2440: '=' : cannot convert from 'ResizeCallback *' to 'ResizeMemberCallback *'
int TestManager::registerResizeFunction(ResizeCallback * resizeFunctor){	ResizeCall newResizeCall;	static id = 0;	id++;	newResizeCall.first = id;-->	newResizeCall.second = resizeFunctor;	resizeVector.push_back(newResizeCall);	return id;}



error C2228: left of '.OnResize' must have class/struct/union type
void GLFWCALL TestManager::windowResize(int width, int height){	CallbackVector::const_iterator iter;	// Call functions in the vector	for (iter = resizeVector.begin(); iter != resizeVector.end(); ++iter)	{-->		iter->second.OnResize(width, height);	}}
<a href="http://ruggles.hopto.org>My Personal Website
Quote:Original post by ChaosX2
I didn't mean that the way it sounded. So basically what I did was created a monostate singleton which is kind of redundant. So which is the preferred pattern, monostate or singleton? I'm thinking singleton.


I am filled with absolute loathing for the singleton pattern.

I sometimes use the monostate one.

That said, lots of (<opinion>crazy</opinion>) people use singletons. Enough that they're likely more popular. That dosn't necessarily mean best, though.

They both achieve the same basic thing (one set of data), with different "gotchyas" - the singleton pattern enforces a rule of 1 element, and thus is harder to expand when you suddenly need 2+ of something. On the other hand, two seemingly seperate objects sharing the same data (monostate pattern) can be an unexpected/confusing, bug causing gotchya.
Quote:Original post by ChaosX2
The code you posted doesn't seem to compile. Here are the errors I'm getting

error C2440: '=' : cannot convert from 'ResizeCallback *' to 'ResizeMemberCallback *'
*** Source Snippet Removed ***

Are you sure your vector used ResizeCallback* and not the ResizeMemberCallback*?
You have to use the base class for the vector, not the derived class.
Quote:
error C2228: left of '.OnResize' must have class/struct/union type
*** Source Snippet Removed ***

Typo, mea culpa [smile]
This should read "iter->second->OnResize(width, height);", since the second member of the pair is a pointer.

[edit]
I just hacked together a small test app and it works without problems.
Here's the source:
#include <algorithm>#include <cassert>#include <iostream>#include <string>#include <vector>// --------------------------------------------------------------------------------//                    CALLBACK STUFF// --------------------------------------------------------------------------------// base class, not really necessaryclass Callback {};// resize callbackclass ResizeCallback : public Callback{public:        virtual void OnResize( int, int ) { }};// templated resize callback for non-static class memberstemplate<class Callee>class ResizeMemberCallback : public ResizeCallback{    typedef void (Callee::*MethodType)( int, int );    MethodType  callback;    Callee    * callee;public:    ResizeMemberCallback( Callee * c, MethodType method ) : callee( c ), callback( method )    {         assert( c && method );    }    void OnResize( int width, int height ) {         // forward the call to the class instance         (*callee.*callback)( width, height );    }};// --------------------------------------------------------------------------------//            STRIPPED DOWN WINDOW MANAGER - JUST FOR TESTING CALLBACKS// --------------------------------------------------------------------------------class WindowManager{private:   // pointers or references must be used, since polymorphism is at work here   typedef std::pair<int, ResizeCallback *> ResizeCall;   typedef std::vector<ResizeCall>          CallbackVector;   // the vector now holds a pair of <id, Functor>   CallbackVector                           resizeVector;   // find by id functor   struct HasId {       // ctor.       HasId( int id ) : id( id ) { }       int id;       // function operator, allows a call like "HasId hasId(x); hasId( call );"       bool operator( )( ResizeCall const & call ) const { return call.first == id; }   };   // singleton stuff   WindowManager() { }   // hide assignment operator   WindowManager const & operator = ( WindowManager const & );public:   ~WindowManager();   // register callbacks   int registerResizeFunction(ResizeCallback * resizeFunctor);   // unregister callbacks   void unregisterResizeFunction(int id);   // invoke callbacks   void windowResize(int width, int height);   // singleton stuff   static WindowManager * getInstance( ) {    static WindowManager instance;; return &instance; }};// delete pointers hereWindowManager::~WindowManager(){        std::clog << "Deleting " << resizeVector.size() << " windowResize callback(s)\n";        for ( size_t i = 0; i < resizeVector.size(); ++i )             delete resizeVector.second;	resizeVector.clear();}// note that the windowmanager takes ownership of the pointer and that// the resize functor must be created using "new"int WindowManager::registerResizeFunction(ResizeCallback * resizeFunctor){	ResizeCall newResizeCall;	static id = 0;	id++;	newResizeCall.first = id;	newResizeCall.second = resizeFunctor;	resizeVector.push_back(newResizeCall);	return id;}// find the documentation for "remove_if" in your STL docsvoid WindowManager::unregisterResizeFunction(int id){        // find the callback and remove it by moving it to the end	CallbackVector::iterator iter = std::find_if( resizeVector.begin( ),           resizeVector.end( ), HasId( id ) );        // erase it (there can only be one)        if ( iter != resizeVector.end( ) ) {            std::clog << id << " has been removed\n";            delete iter->second;            std::swap( resizeVector.back( ), *iter );            resizeVector.pop_back( );        }        else std::clog << id << " was not found\n";}// invoke callbacksvoid WindowManager::windowResize(int width, int height){	CallbackVector::const_iterator iter;        std::clog << "Invoking " << resizeVector.size() << " windowResize callback(s)\n";	// Call functions in the vector	for (iter = resizeVector.begin(); iter != resizeVector.end(); ++iter)	{		iter->second->OnResize(width, height);	}}// wrapped free functionstruct MyResizeFunctor : public ResizeCallback {    void OnResize( int width, int height ) {         std::clog << "MyResizeFunctor: " << width << "x" << height << "\n";    }};// --------------------------------------------------------------------------------//            			CALLBACK EXPAMPLES// --------------------------------------------------------------------------------// class with self-registering callbackclass MyClass {   void Resized( int w, int h ) { std::clog << "MyClass: " << w << "x" << h << "\n"; }   int resized;public:      MyClass( ) {       resized = WindowManager::getInstance()->registerResizeFunction( new ResizeMemberCallback<MyClass>( this, Resized ) );   }   ~MyClass( ) {       // unregister       WindowManager::getInstance()->unregisterResizeFunction( resized );   }};// --------------------------------------------------------------------------------//            			DRIVER PROGRAM // --------------------------------------------------------------------------------int main(){    // test self-registering    MyClass clazz;    // test dynamic register/unregister    MyClass * dynamic = new MyClass;    // add "free function"    WindowManager::getInstance()->registerResizeFunction( new MyResizeFunctor );    // invoke    WindowManager::getInstance()->windowResize( 10, 120 );    // unregister    delete dynamic;    // invoke    WindowManager::getInstance()->windowResize( 50, 5 );    // "clazz" should remove itself upon destruction    return 0;}

Rip it apart and integrate what you need - it's a gift for you [smile]
Merry christmas!
[/edit]


[Edited by - darookie on December 23, 2005 9:45:18 AM]
Quote:Original post by darookie
Are you sure your vector used ResizeCallback* and not the ResizeMemberCallback*?
You have to use the base class for the vector, not the derived class.


D'oh...

Quote:Original post by darookie
Typo, mea culpa [smile]
This should read "iter->second->OnResize(width, height);", since the second member of the pair is a pointer.


I should have caught that one...

Quote:Original post by darookie
I just hacked together a small test app and it works without problems.
Here's the source:
*** Source Snippet Removed ***
Rip it apart and integrate what you need - it's a gift for you [smile]
Merry christmas!


Thanks so much...
<a href="http://ruggles.hopto.org>My Personal Website
darookie your code works fine on windows but when I compile it on Mac OS X (Xcode) I recieve the following error:

Quote:error: no matching function for call to 'ResizeMemberCallback<MyClass>::ResizeMemberCallback(MyClass* const, <unknown type>)'

note: candidates are: ResizeMemberCallback<T>::ResizeMemberCallback(T*, void (T::*)(int, int)) [with T = MyClass]


Is this standard C++?
<a href="http://ruggles.hopto.org>My Personal Website

This topic is closed to new replies.

Advertisement