Game Design Help
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.
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
something like that, this is just something I whipped up so no gaurentees =)
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 =)
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?
So you're basically saying go with the singleton?
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.
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
WindowManager.cpp
WindowManager.h
#include <string>#include <vector>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<resizeCallback> 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 <GL/glfw.h> #include "WindowManager.h"//Define static variablesWindowManager* WindowManager::wm_instance = NULL;std::vector<resizeCallback> 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<resizeCallback>::iterator iter; // Call functions in the vector for (iter = resizeVector.begin(); iter != resizeVector.end(); ++iter) { if (iter->id == id) { resizeVector.erase(iter); break; } }}void GLFWCALL WindowManager::windowResize(int width, int height){ std::vector<resizeCallback>::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); }}
Since I received no feedback on this I'm going to assume that there are no inherit flaws in the current structure.
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):
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.
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?
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.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement