Better Scripts,
Better Games
of programming patterns that have proven over time
to be successful. Though developers use these programming patterns in creating game behavior, the scripting
languages usually do not support them explicitly. One of
the reasons object-oriented programming languages have
been so successful is that object-oriented programming
patterns existed long before the languages that supported
them. Similarly, by examining existing programming
practices in game development, we can design scripting
languages that require very little retraining of developers. The challenge in developing a scripting language is
identifying those patterns and creating language features
to support them most effectively.
THE S TA TE-EFFEC T PA T TERN
One popular pattern in game development is the
state-effect pattern. Every game consists of a long-running
simulation loop. The responsiveness of the game to
player input depends entirely on the speed at which the
FIGURE
2
Example of the State-Effect Pattern
// State variables
vector position, velocity;
scalar q, damping, mass;
// Outer simulation loop
for each timestep {
// Effect variables
vector force;
// Compute effects for all
for each particle o {
o.effectPhase();
}
// Update state for all
for each particle o {
o.updatePhase() ;
}
simulation loop can be processed. In the state-effect pattern, each iteration of the simulation loop consists of two
phases: effect and update. In the effect phase, each game
object selects an action and determines individually the
effects of this action. In the update phase, all the effects
are combined and update the current state of the game to
create the new state for the next iteration of the simulation loop.
Because of these two phases, we can separate the
attributes of game objects into states and effects. State
attributes represent the snapshot of the world after the
last iteration of the simulation loop. They are altered only
in the update phase and are read-only in the effect phase.
Effect attributes, on the other hand, contain the new
actions of the game objects, and the state of the game is
updated with effects during the update phase. Because
interactions between game objects are logically simultaneous, effect values are never read until the update phase.
Hence, effect values are, in some sense, write-only during
the effect phase.
Game physics provides many examples of this pattern. At the beginning of the simulation loop, each game
object has a current position and velocity recorded as
state attributes. To compute the new velocity, each object
computes the vector sum of all of the forces acting upon
it, such as collisions, gravity, or friction. In other
words, the force attribute
may be written to multiple
times during the simulation loop, but it is never
read until all of the force
values have been summed
together at the end of the
loop. The example in figure
2 illustrates the use of the
state-effect pattern to simulate objects moving about
in a potential field. The
variable force is an effect
in this calculation. During
the effect phase we only
increment its value and
never read it to determine
control flow. Whereas most
implementations would
read the old value of force
to perform this increment,
this is not necessary; we
could also gather all of
// Read state, write effects
effectPhase() {
for each particle p {
r = position-this.p.position;
s = ((this.q*p.q)/( r.magnitude())^ 3;
force += s*r;
}
}
}
// Read and write state, read effects
updatePhase() {
velocity = damping*velocity+force/mass;
}
22 November/December 2008 ACM QUEUE
rants: feedback@acmqueue.com