One common pattern in games software is what I call, for the lack of a better name, the Game DLL.
DLL is an initialism for Dynamic Link Library, which is the name Windows gives to its dynamic modules.
On Linux, they are the SO (Shared Object) modules. Under Mac, they are called Dynlibs.
The Game DLL pattern is particularly common in games that have a clear separation between
game code and engine code, such as the Quake family of games and also Doom 3.
Basically, it consists in separating the more reusable engine code into one dynamic library, and game specific
code into another: the Game DLL. This promotes separation between the engine team and the game team, which can
work better in parallel. Also, the engine code can be more easily reused on more than one game.
Creating the engine DLL is fairly simple. All you need to do is move any generic, non game specific code into
another project and build it as a Dynamic Link Library. The engine code knows about the game library, which is an
abstract interface. It can hold a pointer to it, but the engine should not link with the game library.
Instead, the engine library loads the game library at runtime, as it is done in the LoadGameDLL() method below,
passing and instance of itself to the game library. It is important that the engine module never links statically
with the game library, so that in theory, the game DLL could be replaced at any time without any changes needed
in the engine side.
The game library interface should be a pure abstract interface, together with any other classes
that must be seen by the engine. This allows the engine library to compile without linking with
the game library. The game library, on the other hand, can link statically with the engine.
All engine interfaces could be abstract, but that is not strictly necessary. The game can have
full knowledge of the engine and link with it directly, since the engine is a foundation framework,
while the game is a case specific thing that shouldn’t interfere with the engine, so the engine
should have minimal knowledge about the game library.
The game library must provide a way for the engine to initialize it once the DLL is loaded by the
proper system calls. For that, we use a factory function: CreateTheGame(). Note that the function
should be declared with C linkage (extern "C"). This is necessary because dynamic library management
APIs in modern Operating Systems won’t let you instantiate a C++ class or call a class method, you can
only fetch pointers to plain functions. C++ mangles function names, while C doesn’t. Declaring the function
with C linkage makes it easier to fetch the function pointer from the game DLL.
Lastly, we will need an executable to tie things together. Again, the game executable only
needs to know about the engine library, and it can be as simple as an empty main() function
that forwards execution to the engine, which will eventually load the game library.