|See what's going on with flipcode!|
Elements Of A Game Engine
by (05 March 2001)
|Return to The Archives|
So lets say your writing a 3D game engine that supports a pretty good set of
features. Your list of desires includes curved surfaces, dynamic lighting,
volumetric fog, mirrors and portals, skyboxes, vertex shaders, particle systems,
static mesh models and animated mesh models. If you have a good idea of how all
these things work, you can probably start putting these things together into an
But wait! Before you start coding you need to think about what you're going to do with your engine. Most likely, you have aspirations of making a game. If you just jump in and start coding an engine, you're gonna get burned and end up having to re-write huge portions of the engine multiple times to add effects and control later. A little forethought into engine design will save headaches and time. The thing you don't want to do is aspire to huge projects. You'll end up not finishing it, and moving onto something else. While this is a way to learn everything you need, you won't be completing things. It's good to actually finish projects. You'll feel better for it and you can show off!
Let's take a look at the basic components of a full-featured 3D game engine. First off, this is for those people are reasonably experienced with 3d but need a little direction. These are not hard and fast rules that you must use. It's just what has worked well for me and to give an overview of how much work and how many parts go into a game engine. I call these parts System, Console, Support, Renderer/Engine Core, Game Interface, Game, and Tools/Data.
During development, you're going to need some data, and unfortunately it's not
going to be as easy as writing some text files that define a cube. At the least
you will need 3d model editors, level editors, and graphics programs. These
things can be bought or you can find a free program online that does the same
type of thing. Unfortunately you're probably going to need more tools than this
and the software doesn't exist yet. You need to write it. You may end up writing
your own level editor if you can't find one that does the things you want.
You'll probably need to write some code to pack files into an archive since
dealing with and distributing hundreds or thousands of files can be a pain.
You'll need to write converters or plug-ins from your 3d model editor format
into your own format. You'll need tools to process game data, such as visibility
computations or lightmaps.|
The basic line is that you'll probably have nearly as much or more code in tools than actual game code. You can find formats and tools that you can use, but sooner or later you'll realize you need some things that are very custom to your engine and you'll end up writing your own anyway.
Although there is a probably a big rush to get tools done just so there are usable, do take care in your coding. Someone may actually try to use, extend or modify your tools one day, especially if you make your engine to be opensource or modifiable.
You should probably be prepared to spend as much time making graphics, levels, sound, music and models as you did writing the game, tools, and engine.
System is the part of the engine that communicates with the machine itself. If
an engine is written very well the system is the only part that should need
major modifications if porting to a different platform. Within the system are
several sub-systems. Graphics, Input, Sound, Timer, Configuration. The System is
responsible for initializing, updating, and shutting down all these sub-systems.|
The Graphics Sub-System is pretty straightforward. If it deals with putting things on the screen, it goes here. One would most likely write this component using OpenGL, Direct3D, Glide, or software rendering. To get even fancier, you could implement multiple API interfaces and put a Graphics Layer on top of them to give users more choice and more chance for compatibility and performance. This is a bit difficult though, especially since not all API's will have the same feature sets.
The Input Sub-System should take all input (Keyboard, Mouse, Gamepad and Joystick) and unify it and allow for abstraction of control. For example, somewhere in the game logic, there will be a need to see if the user wants to move his or her position forward. Rather than doing multiple checks for each type of input, one would make one call to the input sub-system and it would transparently check all devices. This also allows for ease of configuration by the user, and easily having multiple inputs perform the same action.
The sound system is responsible for loading and playing sounds. Pretty straight forward, but most current games support 3D sound and this will make things a little more complex.
Pretty much everything in a 3d game engine (I'm assuming real-time games here...) is based on time. Hence you need some time management routines in the Timer sub-system. This is actually pretty simple, but since anything that moves will move with time, a decent set of routines will keep you from writing the same code over and over.
The Configuration unit actually sits above all the other sub-systems. It's responsible for reading configuration files, command line parameters, or whatever setup method is used. The other sub-systems query this system when they are initializing and running. This makes it easy to change resolution, color depth, key bindings, sound support options, or even the game that gets loaded. Making your engine very configurable just makes it easier to test and allows users to set things up the way they like.
|Ok, I know everyone likes to follow the crowd and have a console like Quake. But it's really a good idea. With console variables and functions you can change settings in your game and your engine without restarting it. It's wonderful for outputting debug information while developing. Often times you'll be needing to examine some variables and outputting the to the console is faster and sometimes better than running a debugger. Once your engine is running, if an error occurs, you don't have to quit the application; you can handle it gracefully and just print an error message. If you don't want your end user to see or use the console, its easy to disable it and no one is the wiser that it's still there.|
|This is a system that is used by pretty much every other system in the engine. This includes all your mathematics routines, (vectors, planes, matrix, etc), memory managers, file loaders, containers (or use STL if you don't roll your own). This stuff is pretty basic and will probably be used in most any project you ever are involved in.|
Ah yes, everyone loves rendering 3D graphics. Because there are so many
different methods of rendering 3D worlds, it's nearly impossible to give a
description of a graphics pipeline that works in all situations.|
Regardless of how you implement your renderer, the most important thing is to make your renderer component based and clean. Make sure you have distinct modules for different things. The sub-sections that I break the renderer into are sections like Visibility, Collision Detection and Response, Camera, Static Geometry, Dynamic Geometry, Particle Systems, Billboarding, Meshes, Skybox, Lighting, Fogging, Vertex Shading, and Output.
Each one of these sections needs to have an interface that easily allows for changes in settings, position, orientation, or any other setting that may be associated with the system.
One major pitfall to look out for is feature bloat. Decide what you are going to implement at the design stage. If you don't adding new features will start to get hard to do and the solutions will be kludgy.
One thing that is nice and convenient is to have all triangles (or faces) ultimately pass through the same point in the render pipeline. (Not a triangle at a time, I'm talking about triangle lists, fans, strips, etc.) It takes a bit more work to get everything into a format that can be passed through the same lighting, fogging, and shading code but in the end you'll be happy that any effect that you can do to one polygon can be done to any polygon in your game simply by changing its material/texture id.
It doesn't hurt to have multiple points from which things are drawn, but it can lead to redundant code if you're not careful.
You'll eventually find out that all those cool effects that you wanted to implement will be 15% or less of the total code you end up writing. That's right, most of a game engine is not graphics.
The most important part of a 3D game engine is that it is a game engine. It is
not a game. The actual game should never have components that are put into the
game engine. Having a thin layer between the engine and the game makes for
cleaner code and ease of use. It's a little extra code, but it also makes a game
engine very reusable and it becomes much easier to use a scripting language for
game logic, or put the game code in a library. If you embed any of your game
logic in the engine itself, don't plan on reusing it later without lots of
problems and modifications.|
So you're probably wondering what this layer between the engine and game provides. The answer is control. For each part of the engine that has any dynamic properties, the engine/game layer provides an interface to modify it. Some things in this category include the camera, model properties, lights, particle system physics, playing sounds, playing music, handling input, changing levels, collision detection and response, and placement of 2D graphics for a heads up display, title screen or whatever. Basically if you want your game to be able to do it, there must be an interface into the engine to do it.
Well, at this point, I can't tell you how to write your game. That's up to you.
You've spent a while writing this amazing engine with a great interface that
will make your game writing process less stressing.|
3D game engines are huge software projects. A single person can write one, but it's not an overnight process. You're probably going to have more than a few megabytes of source code. If you're not motivated to finish it, you won't.
Also don't expect to write a full engine on your first try. Pick a small project that has small requirements in the engine. Work your way up. You'll get there.