Most game engines provide a suite of runtime software components that together provide a framework upon which a game’s unique rules, objectives, and dynamic world elements can be constructed. There is no standard name for these components within the game industry, but we will refer to them collectively as the engine’s gameplay foundation system. If a line between engine and game can reasonably be drawn between the game engine and the game itself, then these systems lie just beneath this line. In theory, one can construct gameplay foundation systems that are for the most part gameagnostic. However, in practice, these systems almost always contain genreor game-specific details. In fact, the line between the engine and the game can probably be best visualized as one big blur—a gradient that arcs across these components as it links the engine to the game. In some game engines, one might even go so far as to consider the gameplay foundation systems as lying entirely above the engine-game line. The differences between game engines are most acute when it comes to the design and implementation of their gameplay components. That said, there are a surprising number of common patterns across engines, and those commonalities will be the topic of our discussions here. 869 870 15. Runtime Gameplay Foundation Systems Every game engine approaches the problem of gameplay software design a bit differently. However, most engines provide the following major subsystems in some form: • Runtime game object model. This is an implementation of the abstract game object model advertised to the game designers via the world editor. • Level management and streaming. This system loads and unloads the contents of the virtual worlds in which gameplay takes place. In many engines, level data is streamed into memory during gameplay, thus providing the illusion of a large seamless world (when in fact it is broken into discrete chunks). • Real-time object model updating. In order to permit the game objects in the world to behave autonomously, each object must be updated periodically. This is where all of the disparate systems in a game engine truly come together into a cohesive whole. • Messaging and event handling. Most game objects need to communicate with one another. This is usually done via an abstract messaging system. Inter-object messages often signal changes in the state of the game world called events. So the messaging system is referred to as the event system in many studios. • Scripting. Programming high-level game logic in a language like C or C++ can be cumbersome. To improve productivity, allow rapid iteration, and put more power into the hands of the non-programmers on the team, a scripting language is often integrated into the game engine. This language might be text-based, like Python or Lua, or it might be a graphical language, like Unreal’s Kismet. • Objectives and game flow management. This subsystem manages the player’s objectives and the overall flow of the game. This is usually described by a sequence, tree or graph of player objectives. Objectives are often grouped into chapters, especially if the game is highly story-driven as many modern games are. The game flow management system manages the overall flow of the game, tracks the player’s accomplishment of objectives and gates the player from one area of the game world to the next as the objectives are accomplished. Some designers refer to this as the “spine” of the game. Of these major systems, the runtime object model is probably the most complex. It typically provides most, if not all, of the following features: • Spawning and destroying game objects dynamically. The dynamic elements in a game world often need to come and go during gameplay. Health 15.1. Components of the Gameplay Foundation System 871 packs disappear once they have been picked up, explosions appear and then dissipate and enemy reinforcements mysteriously come from around a corner just when you think you’ve cleared the level. Many game engines provide a system for managing the memory and other resources associated with dynamically spawned game objects. Other engines simply disallow dynamic creation or destruction of game objects altogether. • Linkage to low-level engine systems. Every game object has some kind of linkage to one or more underlying engine systems. Most game objects are visually represented by renderable triangle meshes. Some have particle effects. Many generate sounds. Some animate. Many have collision, and some are dynamically simulated by the physics engine. One of the primary responsibilities of the gameplay foundation system is to ensure that every game object has access to the services of the engine systems upon which it depends. • Real-time simulation of object behaviors. At its core, a game engine is a realtime dynamic computer simulation of an agent-based model. This is just a fancy way of saying that the game engine needs to update the states of all the game objects dynamically over time. The objects may need to be updated in a very particular order, dictated in part by dependencies between the objects, in part by their dependencies on various engine subsystems, and in part because of the interdependencies between those engine subsystems themselves. • Ability to define new game object types. Every game’s requirements change and evolve as the game is developed. It’s important that the game object model be flexible enough to permit new object types to be added easily and exposed to the world editor. In an ideal world, it should be possible to define a new type of object in an entirely data-driven manner. However, in many engines, the services of a programmer are required in order to add new game object types. • Unique object ids. Typical game worlds contain hundreds or even thousands of individual game objects of various types. At runtime, it’s important to be able to identify or search for a particular object. This means each object needs some kind of unique identifier. A human-readable name is the most convenient kind of id, but we must be wary of the performance costs of using strings at runtime. Integer ids are the most efficient choice, but they are very difficult for human game developers to work with. Arguably the best solution is to use hashed string ids (see Section 5.4.3.1) as our object identifiers, as they are as efficient as integers but can be converted back into string form for ease of reading. 872 15. Runtime Gameplay Foundation Systems • Game object queries. The gameplay foundation system must provide some means of finding objects within the game world. We might want to find a specific object by its unique id, or all the objects of a particular type, or we might want to perform advanced queries based on arbitrary criteria (e.g., find all enemies within a 20 m radius of the player character). • Game object references. Once we’ve found the objects, we need some mechanism for holding references to them, either briefly within a single function or for much longer periods of time. An object reference might be as simple as a pointer to a C++ class instance, or it might be something more sophisticated, like a handle or a reference-counted smart pointer. • Finite state machine support. Many types of game objects are best modeled as finite state machines (FSM). Some game engines provide the ability for a game object to exist in one of many possible states, each with its own attributes and behavioral characteristics. • Network replication. In a networked multiplayer game, multiple game machines are connected together via a LAN or the Internet. The state of a particular game object is usually owned and managed by one machine. However, that object’s state must also be replicated (communicated) to the other machines involved in the multiplayer game so that all players have a consistent view of the object. • Saving and loading / object persistence. Many game engines allow the current states of the game objects in the world to be saved to disk and later reloaded. This might be done to support a “save anywhere” save-game system or as a way of implementing network replication, or it might simply be the primary means of loading game world chunks that were authored in the world editor tool. Object persistence usually requires certain language features, such as runtime type identification (RTTI), reflection and abstract construction. RTTI and reflection provide software with a means of determining an object’s type, and what attributes and methods its class provides, dynamically at runtime. Abstract construction allows instances of a class to be created without having to hard-code the name of the class—a very useful feature when serializing an object instance into memory from disk. If RTTI, reflection and abstract construction are not natively supported in your language of choice, these features can be added manually. We’ll spend the remainder of this chapter delving into each of these subsystems in depth.