Original Post
Hello! I'm embarking on my journey to create my second game engine, an this time I'd like it to be less game specific and more uncluttered. I know the various bits and pieces needed in the engine, an example listing can be found in this post on GameTutorials: I suppose eventLoop() should run in a separate thread. Which is best, to use SDL_Thread or pthreads? Comments? What could be done better? Another problem I see in this approach is that the class Listener must contain much non-general information. Suppose I have a GUI with widgets. A button would want to register a Listener for mouseclicks, but only if they occurred on the button itself. Either I'd let the button react on every mouseclick, and then test if it was over the button itself. I would much rather connect Listener::function to Button::click(), which of course only should be triggered when the mouse cursor is above the button. But then the event system must be aware of the buttons dimension, maybe by passing the button boundaries to the listener. That wouldn't be nice now, would it? Another thing that I can't get a grip on is how everything should be encapsulated. Should every subsystem be implemented as a class? Running in its on thread? Wouldn't it seem silly to implement classes which only will be instantiated once during execution (one event-handler, etc.)? I need some ideas how they should be structured and derived from each other. I tried one method where I would place everything as independent functions in different namespaces like, game::graphics, game::sound, game::gui, game::events, you get the idea. But I didn't really like that solution. Cheers, Stefanos Carlström
Quote:What I want to know is how I should tie this together. I know that the different subsystems should be oblivious of each other, and that they should be interconnected by an event system. I thought this system up:
- Rendering engine - Sound engine - Some kind of AI system - player control - A camera - Collision and physics - A way to describe game objects - A file loader, or a collection of file loaders Now start to add in some details inside the boxes of the subsstems... - Rendering engine - Texture manager (for loading and storing textures) - A way to handle, store and draw meshes - A way to draw the world (might be the same as the way you draw meshes) - An animation system - A frustum - A particle system - A way to draw 2D stuff and text for the HUD and menus - Sound engine - A way to stream music and speech - A manager for smaller sounds to be loaded and played when you want them - Some kind of AI system - A generic state machine - A way to create states and fit them together - Pathfinding - player control - Some kind of raw input handler (keyboard? Mouse? Joypad?) - A way to turn the raw input into game actions - Collision and physics - A way to represent different collidable shapes (spheres, boxes, cylinders etc) - A way to collide with the world (BSP? Octree?) - A way for objects to collide with each other - A way to work out what's happened when collisions occur - A way to describe game objects - A structure you can fill in a variety of different ways to represent different things (Remember code reuse is the key here, so the game object shouldn't do much in itself, just draw together bits of other things) - A hierarchy? A group of hierarchies? Something totally different? - A manager to look after all the entities - A file loader, or a collection of file loaders - A common interface? - A collection of different loaders, one for textures, one for meshes, one for the world maybe, one for sounds, one for data files... - A memory manager
class Listener{
boost::function<void ()> function;
public:
void call(){
function();
}
setFunction(boost::function<void ()> inFunction){
function=inFunction;
}
}
std::list<int> messageQueue;
std::vector<Listener> listeners;
int crc(string text){
//Return CRC of text
}
void sendMessage(string message){
messageQueue.push_back(crc(message));
}
void checkInput(){
//A lot of checking going on here
//...
//Eg. ESC button pressed
if(BUTTON=ESC){
sendEvent("key escape pressed");
}
//...
}
void pumpMessages(){
//While there's still something in the message queue,
//process it
while(messageQueue.size()){
//If there's a listener registered for
//the message messageQueue[0], call its
//registered callback
for(unsigned int i=0; i<listeners.size(), i++){
if(listeners.getMessage()==messageQueue[0]){
listeners.exec();
}
}
messageQueue.pop_front();
}
}
void eventLoop{
while(running){
checkInput();
pumMessages();
}
}