Game Design Help

Started by
19 comments, last by ChaosX2 18 years, 3 months ago
I'm trying to design a simple 3D Space game and I'm having a little issue with some design concepts. I know I need a Window Manager/Input Manager/Graphics Manager. I originally wrote the window manager as a class. I ran into problems with the window resize callback. Any time a window is resize I need to perform tasks in the graphics manager to adjust the display. So I created a callback method, but you can't use a class method for callback unless it's a static method. Now I'm thinking of either dropping the the Window/Input/Graphics classes and going with a group of functions or re-writting them as singltons. I'd like to get some feed back on what a good solution might be for this simple game.
<a href="http://ruggles.hopto.org>My Personal Website
Advertisement
What API and OS are you using? It seems like if you have a main loop that checks for messages for window messages (for example the MainWindowProc() in windows that you could just make a singleton "Input manager" and then in your main message callback just have case statements deciding what to do or just forward the message recived directly to the input manager who would decide how to handle it.

For example in windows
LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){   //.... other code   Input::Instance()->ReciveMsg(uMsg, wParam, lParam);}//.. Input Classvoid ReciveMsg(UINT uMsg, WPARAM wParam, LPARAM lParam){   switch(uMsg)   {     case WM_SIZE:        int height = HIWORD(lParam);                int width = LOWORD(lParam);        Window_Manager::Instance()->Resize(height, width)        break;   }}


something like that, this is just something I whipped up so no gaurentees =)
____________________________"This just in, 9 out of 10 americans agree that 1 out of 10 americans will disagree with the other 9"- Colin Mochrie
I'm using GLFW as the the input/window API and Windows/Linux/Mac as the target Operating Systems.

So you're basically saying go with the singleton?
<a href="http://ruggles.hopto.org>My Personal Website
Sure I mean this is the kind of thing singleton classes were designed for because its not like you are going to have multiple input classes or window managers so why not use this tool.
____________________________"This just in, 9 out of 10 americans agree that 1 out of 10 americans will disagree with the other 9"- Colin Mochrie
so here is how I implemented the Window Manger. I intend to use a simular design for my input manager. How does it look?

WindowManager.h
#include &lt;string&gt;#include &lt;vector&gt;typedef void (*resizeFunction)(int, int);typedef struct {	// unique id	int id;	// function callback 	resizeFunction function;} resizeCallback;using namespace std;class WindowManager{private:	//constructors	WindowManager();	virtual ~WindowManager();	//static variables	static WindowManager* wm_instance;	static int wm_width;	static int wm_height;	static int wm_red;	static int wm_green;	static int wm_blue;	static int wm_alpha;	static int wm_zbuffer;	static int wm_stencilBuffer;	static bool wm_fullScreen;	static string wm_windowTitle;	static bool wm_windowCreated;	static std::vector&lt;resizeCallback&gt; resizeVector;	//static private methods	static void GLFWCALL windowResize(int width, int height);public:	//singleton methods	static WindowManager* getInstance();	static void deleteInstance();	//public methods	bool createWindow(int width, int height, int red, int green, int blue, int alpha, int zbuffer, int stencilBuffer, string windowTitle, bool fullScreen);	bool createWindow(string windowTitle, bool fullScreen);	bool createWindow(bool fullScreen);	bool createWindow();	//public static methods	static int registerResizeFunction(void (*resizePointer)(int, int));	static void unregisterResizeFunction(int id);};


WindowManager.cpp
#include &lt;GL/glfw.h&gt; #include "WindowManager.h"//Define static variablesWindowManager* WindowManager::wm_instance = NULL;std::vector&lt;resizeCallback&gt; WindowManager::resizeVector;int WindowManager::wm_width = 640;int WindowManager::wm_height = 480;int WindowManager::wm_red = 8;int WindowManager::wm_green = 8;int WindowManager::wm_blue = 8;int WindowManager::wm_alpha = 8;int WindowManager::wm_zbuffer = 24;int WindowManager::wm_stencilBuffer = 0;bool WindowManager::wm_fullScreen = false;std::string WindowManager::wm_windowTitle = "3DSCS Window";bool WindowManager::wm_windowCreated = false;WindowManager::WindowManager(){	glfwInit();}WindowManager::~WindowManager(){	glfwTerminate();	resizeVector.clear();}WindowManager* WindowManager::getInstance(){	//check to see if the object has been created	if (!wm_instance) 	{			//create the Window Manager Object and store it		//in the instance pointer		wm_instance = new WindowManager;	}	// Return the instance pointer	return wm_instance;}void WindowManager::deleteInstance(){	//check to see if the object has been created	if (wm_instance) 	{			//delete the object		delete wm_instance;		wm_instance = NULL;	}}bool WindowManager::createWindow(int width, int height, int red, int green, int blue, 							int alpha, int zbuffer, int stencilBuffer, std::string windowTitle,							bool fullScreen){	// Set Variables	wm_width = width;	wm_height = height;	wm_red = red;	wm_green = green;	wm_blue = blue;	wm_alpha = alpha;	wm_zbuffer = zbuffer;	wm_stencilBuffer = stencilBuffer;	wm_fullScreen = fullScreen;	wm_windowTitle = windowTitle;		//Create Window	return createWindow();}bool WindowManager::createWindow(string windowTitle, bool fullScreen){	// Set Variables	wm_fullScreen = fullScreen;	wm_windowTitle = windowTitle;		//Create Window	return createWindow();}bool WindowManager::createWindow(bool fullScreen){	// Set Variables	wm_fullScreen = fullScreen;	//Create Window	return createWindow();}bool WindowManager::createWindow(){	//check to see if window created = false	if (wm_windowCreated) return false;	//initialize return value	int returnValue = 0;		//create window through GLFW	if (wm_fullScreen)	{		returnValue = glfwOpenWindow(wm_width, wm_height, wm_red, wm_green, wm_blue, wm_alpha,									wm_zbuffer,wm_stencilBuffer, GLFW_FULLSCREEN);	}	else	{		returnValue = glfwOpenWindow(wm_width, wm_height, wm_red, wm_green, wm_blue, wm_alpha,									wm_zbuffer,wm_stencilBuffer, GLFW_WINDOW);	}	//check for errors	if (!returnValue)		return false;		// Set window title	glfwSetWindowTitle(wm_windowTitle.c_str());		//register with glfw window events	glfwSetWindowSizeCallback(windowResize);	//get values from glfw	wm_red = glfwGetWindowParam(GLFW_RED_BITS);	wm_green = glfwGetWindowParam(GLFW_GREEN_BITS);	wm_blue = glfwGetWindowParam(GLFW_BLUE_BITS);	wm_alpha = glfwGetWindowParam(GLFW_ALPHA_BITS);	wm_zbuffer = glfwGetWindowParam(GLFW_DEPTH_BITS);	wm_stencilBuffer = glfwGetWindowParam(GLFW_STENCIL_BITS);	return true;}int WindowManager::registerResizeFunction(void (*resizePointer)(int, int)){	resizeCallback newResizeCall;	static id = 0;	id++;	newResizeCall.id = id;	newResizeCall.function = (resizeFunction)resizePointer;	resizeVector.push_back(newResizeCall);	return id;}void WindowManager::unregisterResizeFunction(int id){	std::vector&lt;resizeCallback&gt;::iterator iter;	// Call functions in the vector	for (iter = resizeVector.begin(); iter != resizeVector.end(); ++iter)	{		if (iter-&gt;id == id)		{			resizeVector.erase(iter);			break;		}	}}void GLFWCALL WindowManager::windowResize(int width, int height){	std::vector&lt;resizeCallback&gt;::iterator iter;	wm_width = width;	wm_height = height;	// Call functions in the vector	for (iter = resizeVector.begin(); iter != resizeVector.end(); ++iter)	{		(*iter).function(width, height);	}}
<a href="http://ruggles.hopto.org>My Personal Website
Since I received no feedback on this I'm going to assume that there are no inherit flaws in the current structure.
<a href="http://ruggles.hopto.org>My Personal Website
Why is your data static if you have a singleton?
Also, you can use callbacks with class methods, e.g. using boost.function or with signals.

Yet another method is using your own callbacks (if you don't like depending on boost or a signal library):
// 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 );    }};

Unfortunalety the above forces you to use pointers in your callback vector and
the sample code doesn't provide any value-semantics. Boost.Function is far superior and should be preferred.

HTH,
Pat.
I'd prefer to use as few third party libraries as possible. I thought about creating a callback class like you proposed as a way of not using static variables. The only questions I have is why would using static data be a bad thing for a singlton?
<a href="http://ruggles.hopto.org>My Personal Website
Quote:Original post by ChaosX2
The only questions I have is why would using static data be a bad thing for a singlton?

I didn't say it's a bad thing - don't put words in my mouth [smile].
I just asked why they are static, because they don't have to be.
If you use static member variables, you get a Monostate. While a singleton ensures that there is only one instance of the class, a monostate ensure that all instances share the same state (e.g. data). You have create a singleton monostate, which is - um - let's just say "not a commonly applied pattern" [wink].

In conclusion, either use a singleton, which implies that none of your data - except for the singleton instance itself - needs to be static. Or use a monostate, which implies all your data is static so you won't need a singleton instance (all instances would operate on the shared static data).

Hope that clears things up a little and sorry for the confusion,
Pat.
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.

By the way thanks for the feedback, thats the kind of information I was looking for.
<a href="http://ruggles.hopto.org>My Personal Website

This topic is closed to new replies.

Advertisement