Archived

This topic is now archived and is closed to further replies.

Structural

Engine approach

Recommended Posts

A question for those of you who have written a game engine: How do you approach your engine from your code? - Do you use a message system? posting messages to the engine, then the engine evaluates to which component the message is supposed to go. Also the engine approaches the game through the same message system. Basically you get an event driven engine. - Do you have a load of public functions that drive the engine? For example OpenWindow, or LoadModel. If so, can your engine give events to the game, or does the game have to poll for changes? - Is your engine completely script driven? You could also use scripts to control your engine. Load keymaps, or resources through a script file. The reason I''m asking is because I''m now working on a personal project that uses the message driven approach. The problem is that the number of messages is huge and I have several different message structures (though in the message handler they are all represented as a single block of data). I have messages for creating menu components, to create windows, to notify the game of mouse and keyboard input, to add models, etc etc. And I need several lines of code to fill a message structure with correct data and post it to the engine. I have the feeling I have to write more code to get the same thing done. So, tell me, what is the best approach? And how (if possible) can I make my code more efficient (in the sense of coding)?

Share this post


Link to post
Share on other sites
Now, while I haven''t completed an engine per say, I''ve often struggled with this very question.

Personally, I found the message system too much of a hassle. Sure, it makes for some nice decoupling of systems, but the overhead doesn''t seem worth it.

It seems to me most professional engines don''t use message passing (unless I''ve been reading the Homeworld source all wrong) ...

- Ben

Share this post


Link to post
Share on other sites
My engine (which isn't finished), is arranged into modules where each main part of the engine has it's own class. Kinda like this (simplified, of course):


CGame
|
-----------------------------------------------------
| | | | |
CGraphics CInput CSound CObject CScripting
| | | |
Render() GetInput() CMesh LoadLevel()
SetupMatrices() SInput CLight
SRenderingPackage CTerrain



So basically, a CGame object it created, which creates and manages all the objects in a set order. Like it gets input, scripting, then goes to AI, then sound, and then renders.






[edited by - circlesoft on October 8, 2003 5:55:31 PM]

Share this post


Link to post
Share on other sites
This is something I have been struggling with recently myself, and I have been trying over and over to come up with something cool that requires minimal effort to layer a game on top of it.

I guess you could say I am looking for something 'elegant'

Right now, my CGame class calls several member functions to init the required systems (D3D,DI,DS,etc), which are kept track of by member vars inside CGame, and then from there, I use a pointer to a game state object, which is a hierarchy off a base game state class, ... so each gamestate I make knows how to update/render itself... but I have to pass in the d3d device to each of these everytime I create it, which seems useless... or inelegant. I can't think of a nice way to tie together the subsystems.

Ok, I'm gonna stop rambling since I can't seem to collect my thoughts.. seems to be what happens when I try to think of how I should really make the engine.

I just don't see the whole picture yet.




------------------------------------------------------------
// TODO: Insert clever comment here.

[edited by - drowner on October 8, 2003 1:40:53 PM]

Share this post


Link to post
Share on other sites
@CircleSoft:
Yes, but how does it communicate with the rest of the game?

I also have a modular design, with modules that can be compared to those of you. Each is derived from CTask and are managed by a task manager, which is no more than a loop that calls their update() function each cycle.
But the big question is, how do I get my data into the engine? And how do I get my engine data to my game?
The message approach is good for a generic approach. You use the same message type for each module. But the big disadvantage is that there is no option to request data from the engine the moment you need it.

For example:
Game wants to know the position of somesort of object
Game: Post message to the engine to get the position
Engine: finish cycle
Engine: Once the object manager is update()-ed the manager posts a message to the game about the position
Engine: Launch some more update()'s, untill it launches the games update
Game: Retrieve messages, and then get the position of the object.

Also, you need tonnes of lines of code to actually prepare a message to be posted.

Ofcourse, you could use pointers to point to the object directly, but then you require the game to actually know the classtype of your object.


Someone else poked me with an idea of how to get data on request. Perhaps you can use function pointers (passed through the message system on startup) to call certain functions, like getPosition() (for example). You don't have to know the object type then and you can still call it.

However, this all seems a lot of hassle to me to use a message system AND a function pointer system. This defies the idea of having one genric method of approach.

Oh, oh... and another idea just popped up. Perhaps you can write a conversion layer that simplifies the message posting. Then you can still keep the message system for commands that are not used very much, and use the conversion layer to post frequently used messages (like enabling/disabling menu items for example).

So many ideas spinning around in my head, and no clear view of what is the best.

[edited by - structural on October 8, 2003 1:40:35 PM]

[edited by - structural on October 8, 2003 1:42:17 PM]

Share this post


Link to post
Share on other sites
If you look under CGraphics in my diagram, you see one SRenderingPackage. This is essentially one very large structure that contains vectors of all the object types. There is one vector for generic mesh objects, another for water objects, terrain objects, lights, and so on. The base SRenderingPackage is a member in CGame. The renderingPackage is populated when the level is loaded. A pointer to it is passed to CGraphics, which loops through every object, culls them, and then renders.

This whole idea of a structure that encompasses all the objects and then can be passed to each module (if they need it) allows all the realtime info that is needed to be shared.

I hope that makes a little bit of sense




[edited by - circlesoft on October 8, 2003 5:55:44 PM]

Share this post


Link to post
Share on other sites
As for finding information in one class like: the video, that needs to know a value of something in the scripting class just to say. You could use a pointer in the indivual modules that points back to the CGAME class and basically allowing you to query whatever you may want inside the CGAME and it''s modules. I''ve done something similar, but I always seperated the modules,

I don''t know why, but I never thought of putting the modules inside the game class itself... it makes so much more sense. Thanks circlesoft.

Share this post


Link to post
Share on other sites
I have just started designing an simple engine as a learning project, it will most likely by a message based system.
There are some more overhead, but it will be very flexible and also easier to debug (just dump all messages). It also makes networking more easy, and since this is a multiplayer engine that is a big plus.

Share this post


Link to post
Share on other sites
quote:
Original post by circlesoft
If you look under CGraphics in my diagram, you see one SRenderingPackage. This is essentially one very large structure that contains vectors of all the object types. There is one vector for generic mesh objects, another for water objects, terrain objects, lights, and so on. The base SRenderingPackage is a member in CGame. The renderingPackage is populated when the level is loaded. A pointer to it is passed to CGraphics, which loops through every object, culls them, and then renders.

This whole idea of a structure that encompasses all the objects and then can be passed to each module (if they need it) allows all the realtime info that is needed to be shared.

I hope that makes a little bit of sense



I think I see your point.
So you see your top-level modules as managers for the lower-level modules. But the game can still access the lower-level modules to perform operations on them.
So, in case of your CGraphics module, it manages the render package. It draws it to the screen.
But your game also knows about the renderpackage and can populate it.

That''s quite interresting. Leave the full hierarchial (spelling?) model and use a combination of hierarchy and all-know-all.
Hierarchy between the CGraphics and Rendering package
All-know-all between the game and rendering package.

Feel free to correct me if I''m wrong, but I like that idea!

Share this post


Link to post
Share on other sites
The way my engine works so far is the client app initializes the engine kernel (mKernel.dll) and the kernel then initializes most of the mandatory subsystems such as the event logger, the main timer, various dev-time systems (if in debug mode), and eventually the renderer subsystem and scene manager. When the kernel is initialized it will use the appropriate renderer dll (e.g. mOpenGL.dll) and use that renderer.

Then the client app will create a render window and that render window will come from the kernel after you have initialize all subsystems and the renderer. Once the engine has created a window for you you can instantiate a scene manager and that will give you access to various things such as adding objects to the scene. You also have lower level access to the renderer which gives you the ability to do even more.

There is a lot that I want to do to the engine and this structure may very well change. I do however want to keep the window a part of the engine, because this way the client app needs to only have a main(). You can go ahead and check it out if you'd like at the link in my sig, the latest iteration I'm working on (0.0.6) has a lot of changes and it's always improving.

James Simmons
MindEngine Development
http://medev.sourceforge.net

[edited by - neurokaotix on October 8, 2003 3:42:22 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Structural
That's quite interresting. Leave the full hierarchial (spelling?) model and use a combination of hierarchy and all-know-all.
Hierarchy between the CGraphics and Rendering package
All-know-all between the game and rendering package.

Feel free to correct me if I'm wrong, but I like that idea!


I think you have the right idea. The CGame object calls a function that oversees the rendering in CRender. Passed to it is the SRenderingPackage structure. The render method inside CRender then loops through every object inside SRenderingPackage and renders them (also culls and some other stuff).

You can see some screenshots of the engine if you click on my sig. They are pretty outdated, however, so I'll post some new ones soon.




[edited by - circlesoft on October 8, 2003 5:55:10 PM]

Share this post


Link to post
Share on other sites
I''m working on my first coherent engine right now, and it has some interesting features, although I haven''t really tied it together that well.

This is primarily a gfx engine. The other components are pretty much ignorant of it. Like I said, I haven''t tied it into any sort of coherent game yet, so it''s kind of scattered.

Most of the components are completely ignorant of each other''s existence. The only thing they use are some global types (vector, matrix, and the math related to it) and an "engine" whose main responsibility is to provide GL init/deinit, extensions, and common includes for all graphics related stuff.

So if I want a quake 3 map, I say #include "q3bsp.h" and then declare a CQuakeMap. I then load my map and interact with it via the stuff exported from CQuakeMap, and when I need the map drawn, I use .Render(). The map actually requires a reference to a camera for the frustum culling stuff, which it takes at the Render call. If I want a player, I declare a CPlayer and that has it''s various functions for doing stuff. As it stands, most of the engine is heavily seperated from it''s other pieces and only takes the occasional reference to another component.

I''m working on the GUI as I speak (sort of) and it''s looking a little different. Again, the GUI is seperate from everything else. But inside, all the various components are basically one large inheritance chain. I am still hacking out the messaging structure, but it is looking like the top level window manager will take all events, and then redistribute all of those events to each of those children. They will again take the events and distribute as necessary, etc.

But this is mroe a collection of classes than anything else. Without a proper game around it, it''s hard to say how this will change. There are no public functions at all--everything is in classes. I actually suspect a lot more event-driven stuff will start when an actual game forms, and there are events to deal with But right now, it''s like a bunch of legos that fit together neatly but are easily pulled apart if needed.

Share this post


Link to post
Share on other sites
Here's a topic to throw in, by the way ...

One thing I've always had issues with, is the idea of a singleton. Not the design pattern, or how to implement it, but just the very fact of having some class which does only one thing. Why use a C++ object when there's only ever one instance of it? What's the benefit of that?

I mean, it seems to more logical to me that for "classes" of that type, to eliminate the class and call functions in a C fashion. Sure, use namespaces and what to manage your code, I don't care. This way there's no need for passing a bunch of pointers to every module necessary, just an include file.

Do people do this? Pros/cons?

- Ben

[edited by - carb on October 8, 2003 6:55:28 PM]

Share this post


Link to post
Share on other sites
My understanding is that a singleton is the oop way of doing a global class - Heres a link to Eckels ''thinking in patterns'' the code examples are java but the explanations are good:

http://www.mindview.net/Books/TIPatterns/

Share this post


Link to post
Share on other sites
I always thought singletons were kind of dumb...

That may be because I find occasions where it can be useful to have multiple instances of managers for various things.

Share this post


Link to post
Share on other sites
Who's to say C can't be OOP though? OOP is also a framework of thinking ... If I define my object "renderer", not in the traditional class sense but through a series of functions, and this way it can be thought of as a singleton, what's the difference? To me, it's just I prefer to call rnd::DrawScene (where rnd is the namespace, or even call the function rndDrawScene, if you prefer) instead of through a singleton design pattern like so: CRenderer::GetSingleton().DrawScene(). That seems like a silly amount of overhead (and written code) to do the exact same thing ... and it's still OOP, imho.

- Ben

[edited by - carb on October 8, 2003 12:34:29 AM]

Share this post


Link to post
Share on other sites