Jump to content
  • Advertisement
Sign in to follow this  
ChaosX2

Game Design Help

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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 Class

void 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 =)

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 <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 variables
WindowManager* 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);
}
}

Share this post


Link to post
Share on other sites
Since I received no feedback on this I'm going to assume that there are no inherit flaws in the current structure.

Share this post


Link to post
Share on other sites
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 necessary
class Callback {
};

// resize callback
class ResizeCallback : public Callback
{
public:
virtual void OnResize( int, int ) { }
};

// templated resize callback for non-static class members
template<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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!