Game Enigne: Putting it all together (design)

Started by
15 comments, last by TheFez6255 17 years, 11 months ago
Greetings! I have huge problems with my conceptual design of a game engine. My basic idea was something like this: 1.) cWindow - class that creates a window, just a very small WINAPI wrapper, with one mayor routine virtual MessageProc(....) like WINAPI. One might override it and trap the messages. 2.) cGraphics - class that wraps arround Direct3D, takes cWindow as input. But there is a problem: when cWindow resizes or requires repaint, how shall it notify cGraphics? For example: WM_SIZE event was rised, cGraphics does not know anything about it but the Direct3D device should be reset. 3.) cEngine - basicaly a state machine or a stack of states. You just push a new state and it becomes active, windows message pump is being overtken and in non messaging moments Update and Render methods are called. But still it requires cGraphics to function and on the other hand cWindow too etc.. etc... The problem is that souch classes are no longer independant, it becomes somewhat of spagetti code. cWindow might require cState or cTimer and on the other hand it also might require cGraphic and cGrpahic requires cWindow etc... etc.. I could use singletons, but I believe with a better design, it would be possible to have a cWindow that can function without any reference to cGraphic and so the basic blocks would be independand. I do not want to produce too many classes, but the basic things sould be stand alone and capable to join with other classes. Thank you in advance.
Advertisement
Well I hate the cClassname thing but here is an idea, make a cEvents class that fires off events that other classes can register to recieve. There has been a lot of writings on this, search google and this site for more info.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

I'm with Mike on this one.. some sort of message pump/event system/client server kinda idea seems to be the best idea. I would suggest you look into boost signals/slots to register and fire events. Its what I have been using and its incredibly well put together.
ASCII stupid question, get a stupid ANSI
I really dislike the way you design it.

What you do is a top down design

cgraphics cengine cwindow.... thats all the top of your engine and so simple that you will fail with your project as soon as you want to create a complex system


In my current design (its both for a 3d editor and a fps engine)

Well I have written some basic subsystems that are required by any decent engine

1. a virtual file system wrapper for physfs + required classes for file access ....
2. texture,material,effect & shader systems
texture represents the texture you load from your harddrive
material represents what you get out of these textures
e.g.: a material defines the material type, the effects that happen on interaction with polygons with this material and which textures are used
a 4 layer blended terrain would get a material assigned

like this
*material 007
*layer 1 = ground1.dds
*layer 2 = ground2.dds
...
*layer n = groundn.dds

3. the whole system depends one a lot of classes and can be reused in any further project so I keep them together and let them interact with another
e.g.: the material,effect and shader managers require access to the filesystem so I chose to use singletons to give access to read in all the shader defs...


Think about you approach if you really want to structure it as simple as you do right now, this cries for design flaws that will lead to failure or cause a ton of work to refactor code.

You should really design your code for reuseability otherwise its pretty hard to come up with a decent app in relatively short time

I am working on my code base for 3 years now and its still far from finished but I really increase my productivity with each day I invest into the code base

just make sure you have unit tested everything long enough or it will lead to nested bugs all over the project and thats really a pain ** *** ***

Summary:
Make your design more complex and let the classes of the individual subsystems interact with each other and tread these subsystems as a whole that is only touched by accessors(e.g.: public getters and setters)

now design you application in a way that you can unify these subsystems to a big whole that works well. The only unreusable and redundant code is that, that links the subsystems and that is a tiny part of the whole project
http://www.8ung.at/basiror/theironcross.html
I would make the seperation between 'engine' and 'library' even more clear...

You could make a base-library (.lib, .dll), which (speaking in the example
of the previous poster) contains your filesystem and a resourcemanager which
can use the filesystem.

Now have your application link with the lib, and inherith from the base
resourcemanager to add specialized behaviour (textureMgr, materialMgr, ...)

Using timer-instances spread out over the code usually give headaches.
Instead, you can abstract Timers away by having your renderloop all
'advanceTime(float elapsedTimeInSeconds)' on your engine-parts.
Only the mainloop has the timer, and updates components on each iteration.

This has the advantage you can easily add things like moviecapture (where
you want a constant framerate, and your hdd won't be quick enough to write
data in realtime), or for making sth like a slowmotion (just scale your
timedelta with some factor in the mainloop).

cState sounds like a perfect canditate for a template/statemachine. YOu
can derive your concrete states from the base-class, and use a generic
statemachine template in which make a few calls to say which transitions
are valid.

>a cWindow that can function without any reference to cGraphic and so
>the basic blocks would be independand.
You could put your windowing system in a seperate library (reusability)
and let it 'talk' to your graphics-system over an abstract interface -
your app can then derive from this interface and make calls to your
'real' graphics-system.

visit my website at www.kalmiya.com
Quote:Original post by Basiror
...
3. the whole system depends one a lot of classes and can be reused in any further project so I keep them together and let them interact with another
e.g.: the material,effect and shader managers require access to the filesystem so I chose to use singletons to give access to read in all the shader defs...


A lot of people would argue the use of singletons is a design flaw. Our engine has 1 singleton and I hate it. It's our logger, there is better ways to do it though but at this point I'm not willing to change it (I didn't make it). There are places for singletons but they should be an exception rather then a common thing (imo).

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Why shouldn t I use singletons when I consider a subsystem as a whole? I won t bloat my code with them, its just a way to access data directly without passing a ton of function parameters

And they have the advantage that you can make them multithreading compatible on the fly opposed to simple global variables.

I see no reason why you shouldn t use singletons. In my opinion every sub system that exists only once should be represented by a singleton.

http://www.8ung.at/basiror/theironcross.html
Because, honestly, if you're using a singleton its normally out of laziness or bad design. Rarely can you flat out say you NEED it as there are normally better ways around it. I'm not sure where you went to school but using globals in all the classes I seen (C++ classes) was a big no-no and earned you docked marks (10% on average PER global up to 50%).

Why does your collision detection subsystem need access to your sound manager? If you only want one instance of either of them, say so in the documentation.

"Try to follow the flow of an app using singletons. (To summarize, any part of the code can call any part of the code at any given time. The joy!)" -- Seriema

Read Washus great writings on "Singletonitis". Part 1, 2, 3.

Here's a link to a GDNet journal entry

If your sound manager needs access to your renderer, you have other serious issues besides singletons anyways ;-)

Like I said, our log manager is a singleton, but a junior coder implemented it and while I was on vacation. It's now all over the engine and the one item I can almost justify as a singleton pattern. But when I have spare time it too will be going the way of the Dodo bird.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Quote:Original post by Mike2343
Because, honestly, if you're using a singleton its normally out of laziness or bad design. Rarely can you flat out say you NEED it as there are normally better ways around it. I'm not sure where you went to school but using globals in all the classes I seen (C++ classes) was a big no-no and earned you docked marks (10% on average PER global up to 50%).


I didn t learn C++ in school. I learned it on my own. And you got a PM why Singletons are no sign of lazyness or bad software design of use properly in the subsystems only where they ought to be used

Clearly nobody would say the use of a singleton to access the sound manager in the collision code is good design.

But using a singleton class type with a well defined access api in a subsystem only that can be considered as a whole is still far better than passing information by messages or passing tons of base class pointers around to access the information needed.

The access semantics of well defined subsystems won t change very much from project to project nor will a well defined codebase change very much so from the point of view of code reuseablility singletons can even improve reuseability.

In my current projects I only have to change 1 line of code to plug in another class implementation without changing the access api at all.



here an example of 3 subsystems

the material/shader system, the geometry manager and the filesystem

both a geometry manager and the material system need access to the filesystem to load in the desired resources.

The access semantics of a filesystem won t change anyway within the next 10 years.: open,close,read write seek ....

Now the material systems provides access to resources like textures ....
so the render needs access to retrieve handles that can be bound

and he needs access to the geometry data
both wont change very much within the next few years

the material system passes the texture data to the graphic card and stores a handle, you can access this handle from the render as described above or you can let the geometry system store the handles in a preprocess at load time so the renderer only needs access to the geometry system in the end

And the number of singletons reduces to a minimum and certainly won t pollute your code in any way .
http://www.8ung.at/basiror/theironcross.html
i have lots of managers. They are not singletons. I have a main device class contains references to all my managers. And all my managers have a reference to the d3d device

So i go like this. (just an example of what it might look like and this has its own issues)

device->getSkinManager()->ActivateSkin(skinID);
device->getEffectManager()->BeginEffect(effectID);
device->getMeshManager()->RenderMesh(meshID);
device->GetEffectManager()->EndEffect();

if a manager needs to know about another manager i pass a pointer and make it a friend class but i only do this as a last resort. E.g. Mesh managers has a reference to my Primitive manager. I cant stand passing references per function. It makes code look ugly.

there could be a design flaw in your singleton and a remote piece of code could use your singleton incorrectly when it shouldnt be touching it at all.

You cant say for certain you wont have more than 1 instance. You might extends your engine to use 2 monitors which uses multiple devices so now you might want another instance of your managers.

It would be nice if you could make class members only public to some functions.
--------------------------------Dr Cox: "People are ***tard coated ***tards with ***tard filling."

This topic is closed to new replies.

Advertisement