I keep things pathologically simple...the simplest design that works is always my path of choice. I choose ugliness and simplicity, with only very very basic object oriented constructs. Granted, everything I do is object oriented, but only in nature (it would make just as much sense if everything I am showing you was just a bunch of functions in .h and .cpp files).
So, lets look at a few of my classes, I've got a few biggies:
-glrenderer
-texture manager
-frustum
-bsp
and a few others which I won't post. Collectively, these classes make up the data and functionality which make up the engine. None of these are singleton classes, I could technically create more than one instance of each, but I don't (no need).
In my main module, I create these objects, globally. Through them you can access and manipulate data. When I want to access these objects, I either use the extern keyword and/or pass them into a helper function as a parameter (Yes, I know, a lot of this is particularly inefficient and slow, e.g. accessing global variables, esp through pointers, is probably the most inefficient computationally speaking).
This is at the top of my main module:
Code:
//All of the main game engine variables
GLRenderer *gpGLRenderer = new GLRenderer(50000,50000);
NTGLAPI *gpNTGLAPI = new NTGLAPI("OPENGL32.DLL");
TextureManager *gpTextureManager = new TextureManager;
FPS_t *gpFPS = new FPS_t;
Frustum *gpFrustum = new Frustum;
BSP *gpBSP;// = new BSP;
TextManager *gpTextManager = new TextManager(500);
PhysicsManager *gpPhysicsManager = new PhysicsManager(100.0f, 5.0f ,METER(5.0f));
Here's how a hovertank accesses the engine functionality to be able to render itself (adding a ms3d model to the renderer, along with some debug stuff, on top of doing a frustum test):
Code:
#include "Hovertank.h"
#include "GLRenderer.h"
#include "Quake3BSP.h"
#include "Frustum.h"
#include "TextManager.h"
#include "PhysicsManager.h"
#include "FPS.h"
#include "GameExport.h"
extern GameExport Export;
extern BSP *gpBSP;
extern GLRenderer *gpGLRenderer;
extern Frustum *gpFrustum;
extern TextManager *gpTextManager;
extern PhysicsManager *gpPhysicsManager;
extern FPS_t *gpFPS;
....
void Hovertank::Render()
{
if(gpFrustum->SphereInFrustum(CurrentState.mPosition,mRadius))
{
Matrix4x4 final_render_mat;
final_render_mat.SetTranslation(&CurrentState.mPosition);
final_render_mat = CurrentState.mMat_Orientation;
gpGLRenderer->AddMS3DModelToRenderer(final_render_mat,mpModel);
}
}
That's the design I use...brute and ugly but ultimately very useful and reusable, easy to design and maintain, etc. I started my design where *everything* required for the engine was in a single interface, but because of that build times went through the roof (change one thing that uses the engine or is the engine functionality to itself and nearly everything in the project is completely rebuilt, whereas with this I can create a palette of the functionality I need).
workspace