Approaching Engine Design

Started by
7 comments, last by gekko 12 years, 9 months ago
I'm a C++ programmer who's interested in programming a decent game engine, a long with one of my friends. I've been going at this for more than a year.

By "decent game engine," I'm talking about an organized, abstracting framework which supports nice 3D graphical features-- such as procedural animation, complex & massive scene graphs, persistent procedural game-worlds, advanced level of detail and so on.

So far, I've made two attempts, which I've decided are poorly designed from the start. Now I need some help.

1) I want to abstract Direct3D 9 in a good way for expanding to other renderers (D3D 11, OpenGL). What might be the best way of doing this? Example?
2) How do I make my engine "modular" ? I really have no clue how this works. Am I supposed to put every "module" in its own *.hpp and *.cpp file pair? Then, besides that, what would be a module?
3) Really, I just want an all around general example of how the engine should be built from ground up.

Please, just answer my questions as best you can.

Thanks,
- King Duck
Advertisement
Write Games, Not Engines -- actually read the article, don't just dismiss it based on the title -- in short, the idea is that unless you've got a lot of experience under your belt you should not approach the problem of writing an engine from the ground-up by itself, but rather should develop one (or preferably more) actual game(s) so that you have a set of real-world requirements to work with. As you work on additional projects you will find certain parts of the code repeated or re-used, and by isolating, abstracting and generalising these components you will end up with a genuinely useful engine that is built to meet the needs of real games; as an added bonus, you'll also have some games you can use to demonstrate the engine's capabilities.


Whenever I see someone asking about modularity I point them in the direction of this post from an old discussion, which takes a step away from the world of software for a moment to examine an excellent example of a modular item: the condom -- it's a great (and funny!) post which helps to illustrate the fundamental concepts behind designing for modularity.

In essence, you need to minimise dependencies so that sections of your code do not rely on other sections if there is no real need to do so. You need to avoid making assumptions about how a piece of code will be used, and not over-engineer it in a way that is potentially restrictive. You should strive to create components that are quick and simple to drop into a project and get working. You probably will divide things up into classes, which will likely be in their own .cpp and .hpp pairs, but it's the higher level concepts rather than the implementation details that will really help you achieve a modular design.


Hope that helps give you a starting point -- I'm sure others will jump in with more specific advice! cool.gif

- Jason Astle-Adams

Create 2 projects.

1 for your engine and one for your first extremely simple 3D game.

create the game putting things that you think might be reusable into your engine project and everything else in your game. Dont worry about reusability AT ALL. when you write things into your engine application dont even think about trying to generilise it so it may work for more things than your first game. Just write it. Spot bad design in existing code but only improve it once your game needs it to be improved.

Do not add stuff to your engine that you think will be neccesary in the future. If you do you will have to rewrite it again anyway once you actualy need it since you didint fully understand the problem at that time due to lack of experience. This is realy important and alot of people doesnt seem to realise this so i cant stress it enough. Only add functionality to your engine when the game youre currently writing demands it!

When youre done with your first game. Start your second game. Make the neccesary changes to your engine as your second game demands it and at the same time keep testing your engine agasint your first game. Of course youl have to make changes to your first game as wel to use the engine's now more generelized functionality.

Repeat this process indefenetley. Always make sure youre older games still work. Modify them as needed.

Slowly but surely with alot of blood sweat and tears youre engine will take shape and get to the point where it can support the developement of a feature rich game with none or very little modification.

The first version of your engine will likely contain little more than a scenegraph
much later you might add some kind of simple entity system
muchmuchmuchmuch later it might get a shader manager and many more
etcetcetc

nice 3D graphical features-- such as procedural animation/abstract rendering/high level of detail

Forget about all of this completely and go make some games. You'l know when to implement those features.

This will vary based on the amount of prior programming experience you have and the amount of time available to you but dont expect to have a "decent game engine" in under 3 years (and thats being very optimistic). And you wont be able to call it "decent" untill you have used it to create a "decent" game without alot of modifications/hacks. Also you better be sure you enjoy solving complex programming problems. You cant have "I would love to have a decent engine" as your only driving force. If you dont get very exited after solving a non-visual problem followed by a burning desire to solve the next problem it simply wont work. You have to seriosly enjoy sitting to 4 am on a weeksday coding on your game/engine even though you know you need to be at work at 8 am. You need to love it so much that you need to force yourself to stop coding at night not force yourself to start.

For me improving my engine is like leveling/farming on a WoW character (It gives me the same feeling). I always tell myself im just gonna finish one more small task and next thing i notice is the sun comming up and i have to be at work in 20 minutes. I seriosly dont see how anyone can by himself succesfuly create a game engine from scratch without this type of mindset. The scope and inner workings of an good game engine is insane.

First, write games.

Next, one approach to support multiple renderers is to inherit the implementation of each renderer from a single, abstract class. This allows your higher level logic to interact with the rendering sections of your game without knowing or caring which underlying API it is using. For example,


// Base Class
class __declspec(novtable) AbstractRenderer
{
AbstractRenderer(void) {};
virtual ~AbstractRenderer() {};

virtual bool InitDevice() = 0;
virtual bool InitSwapChain() = 0;
virtual bool OnResizedSwapChain() = 0;
virtual void OnDraw() = 0;
// etc.
};

// Derived Class
class D3D9Renderer : public AbstractRenderer
{
D3D9Renderer(void);
~D3D9Renderer();

bool InitDevice();
bool InitSwapChain();
// etc.
};

// Somewhere in higher level code land...
std::shared_ptr<AbstractRenderer> renderer;
renderer = std::shared_ptr<D3D9Renderer>( new D3D9Renderer() );
// Or Maybe...
// renderer = std::shared_ptr<D3D10Renderer>( new D3D10Renderer() );
// renderer = std::shared_ptr<D3D11Renderer>( new D3D11Renderer() );
// renderer = std::shared_ptr<OpenGLRenderer>( new OpenGLRenderer() );
// etc.

bool result = renderer->InitDevice();


If you want to pursue something like this further, check out Ogre3D. I'm pretty sure this is how they support directX and openGL.

Finally, in terms of modularity, I'm hesitant to link this, but, I'm going to link it anyways. It's pretty overkill for what you asked, however, I think it's a good example of modular design. Their systems are decoupled in such a way they can begin to attack the problem of concurrency.

I wouldn't be worried about building a concurrent engine. However, decoupling a game's underlying systems would be a reasonable goal.
Thank you all! I'm sure this advice will get me much further. Again, thanks!

Architecture_sm.jpg
Super 3D Game Platform Architecture (Click for Full View)


HI King Duck, my advice to you is to put your engine design on the drawing board first. It really helps to get a Big Picture on how all systems, classes, etc, tie together. I elected to use OGRE which provides a very well engineered abstraction for Direct3D/OpenGL. I've also adopted some the coding techniques used in OGRE into my own Framework code.
Do you really want to spend time programming on a flawless game engine or would you rather concentrate on creating a flawless game? :rolleyes:
1) I want to abstract Direct3D 9 in a good way for expanding to other renderers (D3D 11, OpenGL). What might be the best way of doing this?
Generally through compile-time inheritance like SapphireStorm showed -- though I'd disagree with the use of [font="Courier New"]virtual[/font] and [font="Courier New"]__declspec(novtable)[/font], I'd instead recommend a portable [font="Courier New"]#ifdef[/font] implementation of this concept ;)
2) How do I make my engine "modular" ? I really have no clue how this works. Am I supposed to put every "module" in its own *.hpp and *.cpp file pair? Then, besides that, what would be a module?[/quote]"Modular" is a buzzword. It generally either means "loosely coupled code" or "over-engineered plug-in framework".
Loose-coupling is just a feature of good design. Books like "Large-Scale C++ Software Design" (AKA 'the tome of knowledge' at work) might be of use here.

At work, we make a folder for each "module" of the engine. e.g. there might be a renderer folder, a scene-management folder, an audio-player folder, etc...
If the code in one of these folder includes code from another folder, then that's a dependency between modules. We use a python script to automatically generate a diagram with a circle for each module, and arrows showing the dependencies between them. You could obviously also do this by hand, but the automatic approach allows our lead to realise when people add unnecessary dependencies, and to go and tell them to fix up their design ;)
Ideally, there should be no cyclic-dependencies between modules -- e.g. if [font="Courier New"]scene[/font] depends on [font="Courier New"]renderer[/font], then [font="Courier New"]renderer[/font] must not depend on [font="Courier New"]scene[/font].
The modules and their dependencies end up forming a tree, where at the bottom you've got more isolated "engine-type" modules, like rendering, audio, file-systems, etc... and at the top you've got more "game-type" modules, like character-animation, or special-effects, etc...

If you think that two modules need to communicate with each other (i.e. a type of cyclic dependency), you can usually resolve this design (flaw) by adding a 3rd module which is dependent on both of them. This way the first two modules stay dependency-free and easily maintainable, and the 3rd module's sole responsibility is handling communication between them.
3) Really, I just want an all around general example of how the engine should be built from ground up.[/quote]It depends on [A] what the game design is, what the art/content team's requirements are, and [C] what kind of game-play code needs to be developed. The engine is just a platform that enables those 3 groups of clients to do their job. Without knowing those 3 things, you can't design an engine for them -- hence the whole "make games" attitude when people say that they're making an engine (without also developing a game at the same time).

1) I want to abstract Direct3D 9 in a good way for expanding to other renderers (D3D 11, OpenGL). What might be the best way of doing this? Example?


Direct3D and OpenGL have pretty different APIs, so unless you have experience with both, trying to nail a common interface for the two will be nearly impossible. As for D3D9 vs. D3D11, you should really consider developing in D3D11 and porting back to D3D9. It's much easier follow the new structure which makes heavy use of creation-time validation and "port" that back to D3D9 than it is to take the "make state changes whenever you want" approach from D3D9 and get it running at high performance on D3D11. However, if you're only on PC, you can probably forget D3D9 even exists.
-- gekko

This topic is closed to new replies.

Advertisement