Game Engine System





Every game engine requires some low-level support systems that manage mundane but crucial tasks, such as starting up and shutting down the engine, configuring engine and game features, managing the engine’s memory usage, handling access to file system(s), providing access to the wide range of heterogeneous asset types used by the game (meshes, textures, animations, audio, etc.), and providing debugging tools for use by the game development team. This chapter will focus on the lowest-level support systems found in most game engines. In the chapters that follow, we will explore some of the larger core systems, including resource management, human interface devices and in-game debugging tools. 5.1 Subsystem Start-Up and Shut-Down A game engine is a complex piece of software consisting of many interacting subsystems. When the engine first starts up, each subsystem must be configured and initialized in a specific order. Interdependencies between subsystems implicitly define the order in which they must be started—i.e., if subsystem B depends on subsystem A, then A will need to be started up before B can be initialized. Shut-down typically occurs in the reverse order, so B would shut down first, followed by A. 231 232 5. Engine Support Systems 5.1.1 C++ Static Initialization Order (or Lack Thereof) Since the programming language used in most modern game engines is C++, we should briefly consider whether C++’s native start-up and shut-down semantics can be leveraged in order to start up and shut down our engine’s subsystems. In C++, global and static objects are constructed before the program’s entry point (main(), or WinMain() under Windows) is called. However, these constructors are called in a totally unpredictable order. The destructors of global and static class instances are called after main() (or WinMain()) returns, and once again they are called in an unpredictable order. Clearly this behavior is not desirable for initializing and shutting down the subsystems of a game engine, or indeed any software system that has interdependencies between its global objects. This is somewhat unfortunate, because a common design pattern for implementing major subsystems such as the ones that make up a game engine is to define a singleton class (often called a manager) for each subsystem. If C++ gave us more control over the order in which global and static class instances were constructed and destroyed, we could define our singleton instances as globals, without the need for dynamic memory allocation. For example, we could write: class RenderManager { public: RenderManager() { // start up the manager... } ~RenderManager() { // shut down the manager... } // ... }; // singleton instance static RenderManager gRenderManager; Alas, with no way to directly control construction and destruction order, this approach won’t work.

Post a Comment

0 Comments