PDA

View Full Version : Mechaius Engine Design


Onag
Oct 20, 2003, 06:55 PM
This is where it gets fun for coders. Right now, I'm just coding DirectX and trying to get things working. I'm staying as organized as possible, but I really need a solid code architecture to go off of.

How should we organize the engine? Here's what I've got:

<b>class WindowsShell</b>
Exposes static members and methods for dealing with Windows

<b>class DXEngine</b>
Exposes static members and methods for DirectX initialization and cleanup as well as for drawing frames, playing sounds/music, and receiving input

<b>class TileEngine</b>
Exposes static members and methods for handling tilesets

<b>class SpriteEngine</b>
Exposes static members and methods for handling sprites

<b>class ParticleEngine</b>
Exposes static members and methods for handling particles (snow, rain, dust, fog, fire, smoke, etc.)

<b>class PhysicsEngine</b>
Exposes static members and methods for handling gravity, wind/water currents, and collision detection

Suggestions? I've never done this before, so brutal criticism would be fine.

-Nag

Monolith
Oct 20, 2003, 08:22 PM
This is basically just building off of what you wrote..


Windows Stuff
It's good to have a class that just creates and destroys the window for you.

DirectX
Graphics, input, and sounds really should be split up. They're all basically independent of each other, so there's no reason they should be together.

Graphics
Initialization and global state changes.

Input
Initialization. Getting input and knowing where to hand it off to.

Sound
Initialization of sound stuff. Also possibly manages music and sound effects.

Sound effects
Loads and plays sound effects.

Music
Loads and plays music.

Tileset
Loads tilesets, and manages drawing tiles (or at least handing out tiles for drawing). Probably will also hold collision data for the tiles.

Sprites
Loads and draws a single sprite.

Particle
Just one particle in a particle system

Particle System
Generates one set of particles

Particle Manager
Handles all the particle systems

Physics
Hmm this is hard to put anywhere. It'll probably be the physical object in the object hierarchy.

Objects
There'll probably be a whole hierarchy of these things.

Level
For the actual level information.

Game
For game logic stuff. Might also be used to hold everything else, like the level, tileset, managers, etc.

Program
Basically holds the game, and uses the windows stuff. It should be the only thing in WinMain, I think. (I haven't actually used a component like this in a game yet, but I think it's something that would work well.)

Globals
You don't want to use real global variables. I've found that it works much better to have a class that contains all the globals, and have only one instance of that clase be the only global variable. The way you can ensure everything is constructed and destructed in a safe order.

Time
Just holds and can be queried for the game time and real time.

AI
Might also end up with a hierarchy of AI classes.

Settings
I generally like the idea of not hard coding anything. Instead, stuff like object statistics or whatever should be stored in external files. I've called these 'settings' before, but that might not be the best name because it's more just any data. Basically it's just been a collection of numbers and strings.

HUD
Something to draw the heads up display stuff.

Menu Stuff
This can be a lot of stuff. Depends on how much you want to do with the menu system.

Resource Managers
All those sprites and sounds and stuff need to go somewhere. It's best to have objects just reference them from some sort of bin or manager. One of the imortant things the resource manager does is makes sure the game doesn't crash by giving something a NULL resource, or deleting a resource when it's still in use. Loading and deleting resources would go through these things.

Logger
It's very useful to have a global class that can be used to log debug information to. Basically it just writes to a file, or it could use a windows console.

Quadtree
Most likely we'll want this to optimize stuff like collision. Basically it's just splitting up the world so we only have to check a small set of objects rather than everything at a time.

Object Manager
All those objects/entities/unknowns have to be stored and updated somewhere. Best to keep them all in one place.

Networking
Networking stuff really needs to be considered early on because it's a lot harder to properly insert it into something that's already half made. Generally it seems to be good to always have stuff going through the networking module, and if the game is single player, it just loops back on itself. This is a pretty core component.

There's also stuff like the networking packets and the Winsock wrapper.

Player
Info on the player. Important for multiplayer.

Player Manager
Manages the multiple players. (Wow!)


Ok, that's all I have for now. Whoa, that's a lot of stuff. Didn't realize that when I was writing it. :P

Onag
Oct 21, 2003, 04:55 PM
You don't want to use real global variables.

I'm actually using what are called static classes to provide variables in a global scope. It works similar to your method, but slightly different. A static member/method is one that exists outside of any instance of a class. In other words, if a file knows about a class, it can have access to static members without even creating an instance. For example, given the following files:

<code>-------- globals.h --------

&nbsp;&nbsp;&nbsp;class FakeGlobals
&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HWND HWindow;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static void ShowWindow();
&nbsp;&nbsp;&nbsp;};

---------------------------</code>


<code>------- globals.cpp -------

&nbsp;&nbsp;&nbsp;#include "globals.h"

&nbsp;&nbsp;&nbsp;HWND FakeGlobals::HWindow = NULL;

&nbsp;&nbsp;&nbsp;void FakeGlobals::ShowWindow()
&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ...
&nbsp;&nbsp;&nbsp;}

---------------------------</code>

A file would just have to #include globals.h to have access to the members/methods. For example:

<code>-------- file1.cpp --------

&nbsp;&nbsp;&nbsp;#include "globals.h"

&nbsp;&nbsp;&nbsp;if(FakeGlobals::HWindow != NULL)
&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FakeGlobals::ShowWindow();
&nbsp;&nbsp;&nbsp;}

---------------------------</code>

This seems to work very well so far. There may be a hidden performance hit that I'm unaware of, but unless that proves true, I think I'm going to stick with this method. It makes for very clean code, and avoids the need for using extern.

-Nag

Onag
Oct 21, 2003, 06:01 PM
Graphics, input, and sounds really should be split up. They're all basically independent of each other, so there's no reason they should be together.
Good point, I'll seperate DXEngine into the following static classes:

DirectXGraphics
DirectInput
DirectSound
DirectMusic
DirectShow
DirectPlay (network stuff)

(The names may change.)

Tileset...Sprites...
The TileEngine and SpriteEngine classes will manage the Tile, Tileset, and Sprite classes. Again, these may be renamed for clarity.

Particle...Particle System...Particle Manager...
This is good. I'm thinking the ParticleManager class will handle things like creating and releasing Particles and ParticleSystems, while the ParticleSystem will handle positioning and drawing Particles. Particles are simple data structures with position, velocity, color, and maybe sprite information.

Player...Player Manager...
I'm wanting to handle character movement a bit differently than this. Because essentially any object will be playable, I would like to implement dynamic input mapping for all objects. In other words, when a game begins, the left and right arrow keys will move your character object left and right, but in the middle of the game, these keys can be reassigned to move a stationary missile turret. This way, it will be easy to switch control between characters, vehicals, guided weapons, etc., and allow multiple players on a single input device.

Network...
Any information you have on network code would be great. I know nothing.

-Nag

Monolith
Oct 21, 2003, 09:28 PM
Your static classes appear to be the same as if you just put the globals in a namespace. The one important thing I forgot to mention about how we did globals was that all our global variables inside the globals class were pointers. When we initialized the globals class, the initialization function allocated all the global variables in the order that we chose. Also, in the globals' destroy function, all of the global variables were deleted, in the reverse order. The problem we had before we did this was that some of our global variables (or rather, class instances) were being created or destroyed in the wrong order, and we couldn't control that at all. Now that I think about it again, another solution could have been to assume nothing exists when global classes are constructed, and don't use anything external in a globally used class' destructor. Then you'd just need to be careful of how you initialize and destroy globally used classes. I think the reason we didn't do that for the first project was because we were half way though the project when it occurred, and we didn't want to re-design all the classes.

You might also want particles to be animated, which would make them a little more complex than data structures. Although I don't know how you'd animate particles yet.

Players wouldn't be the actual player objects, but more like the interface between the input and the object the player is controlling. Or.. actually networking does that more. (I'll get into that later.) So I guess players would just be information pertaining to multiplayer stuff.

Ok, so networking...
It seems to work best to design the game such that single player and multiplayer function almost identically. This means player input should be going directly to networking, and the networking stuff should update the game. One of the general rules of game network programming is that the server never trusts anything the client sends. Well, not quite never, otherwise you wouldn't know anything. Basically you want to get stuff from them with as little interpretation by them as possible. Probably not raw mouse input or keystrokes, but the level after that is generally good for clients to send. As for the server side (oh yea, I'm basing all of this on a client-server architecture), the type of updates will depend a lot on how the gameplay works.
All the networking I've worked with before has been with Winsock, and done in threads. I haven't had any experience with DirectPlay, but Winsock has none of the overhead for DirectPlay, and it's simple enough. Threading is used because several networking function can block execution. Actually, I'd need to think more of how it would be best handle the sending/receiving for networking since there are several ways to do it. But I think I'll stop here for now.

Onag
Oct 22, 2003, 12:47 PM
I'll be posting the architecture design progress on the official (temporarily) Mechaius website.

Link: <a href="http://games.inocompany.com/mechaius/index.html">http://games.inocompany.com/mechaius/</a>

Eventually, I'll create a dynamic architecture and documentation system so more than one person can manage it.

-Nag

Hare
Oct 24, 2003, 11:32 PM
Hmm. I read through about everything. I really like Rad's story idea. It is like an enigma of a concept.

Also, I think that it is best if resources were worked on in a priority system. Like, here's the order I typed up for Jazzer X...

Order of priority...
1.Concept
1.1 Extended design rules (restrictions: what we don't want in the game. Basic list)
1.2 Extended design rules (encouraged: things that we want in the game. Basic list)
1.5 Gameplay
1.5.5. Story Stage 1 (concept elaborated)
1.5.9. Story Stage 2 (adding characters, settings, and key moments)
2. Character Design (flesh out characters)
3. World Design (flesh out worlds)
4. Compilation (bring all designed resources together and flesh out the story)
5. Game rules stage 1

-The game design splits into sub groups from this point-

-A-
1. Obstacle Concepts

-B-
1. Scripting Concepts

...Well, this is what I have so far. After number 5, I 'm still working on it, so it isn't very complete. Anyways, there's some stuff I thought was important to get finished before other things are started. I believe it gives the project a firmer foundation. You can see I want a lot of work put into developing the story :). I dunno if this is very similar to what you've already had planned, but anyways I think it may help. Oh, and your feedback would be great :) I also think that there should be administrators appointed to be the head of the different fields of game design. (e.g. Art, Programming, Music, Etc.) Then the people who submit things send their work to the administrator who specializes in such and such area, and the administrators make judgements on what resources would work good, then check things with the Director for his feedback, then things get compiled together. I'm thinking that the programming field shouldn't have scripts flying around all over the place though. That could cause problems. Also the administrators and director also make their own resources for the project, too.

Radium
Oct 25, 2003, 04:24 AM
Order of priority...
1.Concept
1.1 Extended design rules (restrictions: what we don't want in the game. Basic list)
1.2 Extended design rules (encouraged: things that we want in the game. Basic list)
1.5 Gameplay
1.5.5. Story Stage 1 (concept elaborated)
1.5.9. Story Stage 2 (adding characters, settings, and key moments)
2. Character Design (flesh out characters)
3. World Design (flesh out worlds)
4. Compilation (bring all designed resources together and flesh out the story)
5. Game rules stage 1
I'd put 2 before 1.5. It's harder to write a story when you haven't seen final versions of the characters.

Onag
Mar 12, 2004, 09:59 PM
Just an update:

There's been a bit more code discussion over at the <a href="http://www.inocompany.com/forum/">Mechaius Forum</a> to anyone who's interested.

-Nag

Hare
Mar 13, 2004, 01:23 AM
Oh, hey man, Onag, how are things going... Or, actually I'll just clicky the linky and see-ey.