writing good game classes

Started by
10 comments, last by Zipster 19 years, 3 months ago
I am having some problems with game design. I have a simple layout but it doesn't seem to hold up once i begin to write the code for my classes. Here is a very general example design that I would eventually put much more detail into...
WorldManager <- Engine -> InputSystem
    |               |
    V               V
 Objects,          OpenGLWindow
 Textures,
  Menus,
 GameStates,
 Sounds
 etc...
Even a game structure as general as this seems to fall apart when I begin coding because the OpenGLWindow needs to know about the InputSystem and the GameStates need access to the Engine for example. I want to make reusable, flexible classes for my game but I can't seem to keep my subsystems as independant from one another as I would like.
Advertisement
i use d3d not ogl but here is what i have done

// game.h class Game : public Graphics{ protected:   Font arialFont;   Input input;  Camera camera;   int loadScene();  void unloadScene();   void updateScene(float frameTime);   void renderScene(); public:   int run(); };


// graphics.h class Graphics{ protected:   WNDCLASSEX m_wc;  HWND       m_hWnd;   LPDIRECT3D9       m_pd3d;  LPDIRECT3DDEVICE9 m_pd3dDevice;   LPD3DXSPRITE m_pd3dxSprite;   std::vector<LPDIRECT3DTEXTURE9> m_pd3dTextures; public:   HWND               getWindow() { return m_hWnd; }  LPDIRECT3DDEVICE9  getDevice() { return m_pd3dDevice; }  LPD3DXSPRITE       getSprite() { return m_pd3dxSprite; }  LPDIRECT3DTEXTURE9 getTexture(int i) { return m_pd3dTextures; }   void init(UINT width, UINT height, D3DFORMAT format, BOOL windowed);  void cleanup();   void resizeScene(UINT width, UINT height);   void beginScene(D3DCOLOR color=0x000000);  void endScene();   void flip();   void takeScreenShot(LPCTSTR pDestFile);   void setWorldMatrix(D3DXMATRIX worldMatrix);   void loadTexture(std::string file);  void loadTexture(std::string file, LPDIRECT3DTEXTURE9* ppTexture);   void enableBlending(D3DBLEND srcBlend, D3DBLEND destBlend);  void disableBlending();   void enableLighting(D3DCOLOR ambient);  void disableLighting(); };
It's better not to couple your subsystems together too tightly. The typical way to do something like this is using an event system - wherever a subsystem A needs to respond to changes in some other subsystem B, subsystem B sends a message to the event system indicating something specific has happened, perhaps with some relevant data. During initialisation, subsystem A registers with the event system an interestin any message with that type. So, when that particular thing happens, subsystem B tells the event system, and the event system tells subsystem A.

In this way, rather than your input system being tied up with the front end system, the game logic system, the game console etc, every subsystem is coupled only to the event system (where possible).
Harry.
i guess inheriting the Engine from the 'Graphics' or 'OpenGLWindow' would be a lot easier. I didn't know if this was poor design because an Engine is not a Graphics Window.
I previously never used inheritance with this but decided to try it out

I would always have class Graphics a member of class Game and call the access functions like getDevice(), getSprite()

here is a list of my classes

AnimationSequence
Camera
Entity
Font
Frustum
Game
Graphics
Input
Mesh
MultiAnimSprite
Skybox
SkyTexture
Sprite
Timer

here is what my WinMain looks like

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int){   // Enter game loop  Game game;  game.run();   // Exit to Windows  return 0;}


edit:

check out this article

[Edited by - eFoDay on January 7, 2005 10:31:42 PM]
Quote:Original post by eFoDay
this article

That article inspired me. Thanks!
______________________________________________________________________________________With the flesh of a cow.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){		Timmer test_timmer;	Player test_player;	DS_System GameSytem;		//Initialise system	srand(GetTickCount());	console.InitSystem();	if(!console.OpenWindow(SCREEN_X,SCREEN_Y))return -1;			//Init Game System	if(!GameSytem.load_config("system_cfg.txt"))QuitGame(-1);		//Player init	test_player.load_config("player_cfg.txt");	test_player.init(10,10,RIGHT,15);		while(console.System())	{		//Check for Quit Key		if(console.key(GameSytem.QUIT_KEY))break;				//Time Updates		if(GameSytem.update())		{			test_player.update();		}				//Draw the frame		screen = (Gfx_Screen*)console.GetVirtualScreen();		clear_screen();				test_player.render();				if(console.key(GameSytem.CONSOLE_KEY))grid();				console.Update();			}		console.CloseWindow();	console.DeinitSystem();		//Warning elimination for unused variables,I hate such warnings,since they cover really important stuff	hInstance;	hPrevInstance;	lpCmdLine;	nCmdShow;		return 0;}


That's what my code looks like.Each entity is seperate and self-regulated.This code is for a snake game I am developing (I know way too much code,but it's a test run for my next one).

The player class handles a snake class and the input class.And the console class's job is to manage the window.Pretty basic and I dont know if it stands as an example for good design.

Comments anyone?
______________________________________________________________________________________________________
[AirBash.com]
Except for the fact that Timer is spelled with one 'm', you're fine [grin]

And if you want to get rid of those warnings, simply remove the identifiers from the function head:
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)

As long as the signature is the same the compiler doesn't give a rat's ass if you decide not to use a parameter or two (or four) [smile]
Quote:Original post by Zipster
Except for the fact that Timer is spelled with one 'm', you're fine [grin]

Hehe, [grin], happens I suppose ;)

Quote:Original post by Zipster
And if you want to get rid of those warnings, simply remove the identifiers from the function head:
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)

As long as the signature is the same the compiler doesn't give a rat's ass if you decide not to use a parameter or two (or four) [smile]


Thanks a lot.I dint know one could do that.Let me try it out, but I have a fealing it wont work on Borland's compiler.(Btw the code compiles on Borland and on VC++ cleanly).
______________________________________________________________________________________________________
[AirBash.com]
The method that I'm using in my engine currently, is to write interfacing classes everywhere so as to make it API independant(for the most part). If I know that I need an image here, I write an image interface that has a virtual function of what I need. When it comes to everything needs to know about everything, encapsulate the crap out of what you need.

If the sound system needs to know about the input system, then have the sound system have a parent object that knows where the game manager is, have the game manager provide the information about the input system.

Having a child->parent->etc structure isn't violating your class heirarchy. Not everything is completely and solely self-contained. All my tiles have a pointer to the ParentSystem which has access to a lot of data that's needed for what I do. Basically, have a heirarchy of child knows parent knows grandparent until you get what you need.

This topic is closed to new replies.

Advertisement