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.
0 Comments
Please Comment for any further query :