Theory and Practice of Game
Object Component
Architecture
Marcin Chady
Radical Entertainment
Outline
Component-Oriented vs Object-
Oriented Programming
Radical’s approach
Results from [PROTOTYPE]
What are Game Objects?
Anything that has a representation
in the game world
Characters, props, vehicles, missiles,
cameras, trigger volumes, lights, etc.
Need for a standard ontology
Clarity
Uniformity
Feature, staff and tool mobility
Code reuse
Maintenance
E.g. use of modularity/inheritance reduces
duplication
A Game Object Class
Hierarchy
Drawable
(renderable model)
Simulated
(rigid body model)
Trigger
(volume)
GameObject
(transform, refcount)
Prop
Adding Stuff
Drawable
(renderable model)
Simulated
(rigid body model)
Trigger
(volume)
GameObject
(transform, refcount)
Animated
(animation controller)
Animated
(animation controller)
Mix-ins Perhaps?
Drawable
(renderable model)
Simulated
(rigid body model)
Trigger
(volume)
GameObject
(transform, refcount)
AnimatedMixin
(animation controller)
Animated
AnimatedWithPhysics
Observations
Not every set of relationships can
be described in a directed acyclic
graph
Class hierarchies are hard to
change
Functionality drifts upwards
Specialisations pay the memory
cost of the functionality in siblings
and cousins
Change
You can ignore it
You can resist it
Or you can embrace it
But you cannot stop it
Component-Based
Approach
Related to, but not the same as
aspect-oriented programming
One class, a container for:
attributes (data)
behaviours (logic)
Attributes := list of key-value pairs
Behaviour := object with
OnUpdate() and OnMessage()
Components vs
Hierarchies
Prop
GameObject
PedBehaviour
Prototype Game Objects
Data-Driven Creation
Text or binary
Loaded from pipeline
Load and go
Delayed instancing
Dedicated tools
Data-driven inheritance
TOD_BeginObject GameObject 1 "hotdog_concession"
{
behaviours
{
PhysicsBehaviour 1
{
physicsObject "hotdog_concession"
} ,
RenderBehaviour 1
{
drawableSource "hotdog_concession"
} ,
HealthBehaviour 1
{
health 2.000000
} ,
GrabbableBehaviour 1
{
grabbableClass "2hnd"
}
}
}
TOD_EndObject
Advantages
Endowing with new properties is easy
Creating new types of entities is easy
Behaviours are portable and reusable
Code that talks to game objects is type-
agnostic
Everything is packaged and designed to
talk to each other
In short: you can write generic code
Disadvantages
In short: you have to write generic code
Game objects are typeless and opaque
Can’t ask, e.g.
if object has AttachableBehaviour
then attach to it
Code has to treat all objects identically
This is wrong!
Messaging
AttachMessage msg(this);
object->OnMessage(&msg);
Dispatched immediately to all interested
behaviours (synchronous operation)
Fast, but not as fast as a function call
Use for irregular (unscheduled)
processing
Collisions, state transitions, event handling
Can be used for returning values
Attribute Access
The game object must be notified if you
modify an attribute
Const accessor
Read-only access
Cacheable
Non-const accessor
Permits writing
Not cacheable
Sends a notification message to the game
object
Free access from object’s own
behaviours
An attribute or not an
attribute?
Attribute if
accessed by more than one
behaviour, or
accessed by external code
Otherwise a private member of the
behaviour
If not sure, make it an attribute
Game Object Update
GameObject::OnUpdate(pass, delta)
for b in behaviours
b.OnUpdate(pass, delta)
OnUpdate() and OnMessage() are the
only two entry points to a behaviour.
HealthBehaviour Example
void HealthBehaviour::OnMessage(Message* m)
{
switch (m.type)
{
case APPLY_DAMAGE:
Attribute<float>* healthAttr = GetAttribute(HEALTH_KEY);
healthAttr->value -= m.damage;
if (healthAttr->value < 0.f)
mGameObject->SetLogicState(DEAD);
break;
case ATTR_UPDATED:
if (m.key == HEALTH_KEY)
{
Attribute<float>* healthAttr = GetAttribute(HEALTH_KEY);
if (healthAttr->value < 0.f)
mGameObject->SetLogicState(DEAD);
}
break;
}
}
Components in Practice
Behaviours and Attributes
in [PROTOTYPE]
Adoption
Some coders were resistant:
Too complicated
Don’t know what’s going on
Too cumbersome
Calling a function is easier than sending a
message
Reading a data member is easier than
retrieving an attribute
Don’t like typeless objects
Ongoing education
Post-Mortem Survey
0
2
4
6
8
10
12
14
Adoption Coding Debugging Maintenance Reuse Performance Overall
Much worse A little worse About the Same A little better Much better
Post-Mortem Comments
Data-driven creation was the biggest win
Prototyping is the biggest win once you
have a library of behaviours
Modularity of behaviours was the biggest
win
Data inheritance was the biggest win
Components are nothing new - no
modern game could be built without
them
Performance
GameObject::OnUpdate and OnMessage
are easy targets
For the critic
For the optimiser
Existing optimisations:
Message masks
Update masks
Logic state masks
Time-slicing
Attribute caching
Leaving the back door open
Performance Lessons
Best optimisations are algorithmic:
Avoid unnecessary messages, e.g.
object->OnMessage(&message1);
if (message1.x)
object->OnMessage(&message2);
Prefer attributes over messages
Avoid unnecessary updates
Better instrumentation
Legalise the back door entrance
Future Improvements
Stateless behaviours
Submit batches of objects to
stateless behaviours
Better suited for parallel architectures
Message queuing
Prototype’s Data Types
1544 game object definitions
145 unique behaviours
335 unique data types
156 unique prop types alone
0
5
10
15
20
25
30
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47
Number of behaviours
N
u
m
b
e
r
o
f
u
n
i
q
u
e
t
y
p
e
s
Behaviour Usage
0.00%
10.00%
20.00%
30.00%
40.00%
50.00%
60.00%
70.00%
80.00%
R
e
n
d
e
r
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
H
i
t
R
e
a
c
t
i
o
n
B
e
h
a
v
i
o
u
r
G
r
a
b
b
a
b
l
e
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
H
e
a
l
t
h
B
e
h
a
v
i
o
u
r
C
h
a
r
a
c
t
e
r
I
n
t
e
n
t
i
o
n
B
e
h
a
v
i
o
u
r
T
a
r
g
e
t
S
e
l
e
c
t
i
o
n
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
T
h
r
e
a
t
R
e
c
e
i
v
e
r
B
e
h
a
v
i
o
u
r
C
h
a
r
a
c
t
e
r
S
o
l
v
e
r
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
S
h
o
u
l
d
e
r
C
o
n
F
i
x
u
p
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
S
c
a
r
y
M
o
n
s
t
e
r
B
e
h
a
v
i
o
u
r
W
a
l
k
i
n
g
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
H
e
a
l
t
h
S
h
a
d
e
r
B
e
h
a
v
i
o
u
r
L
O
D
R
e
n
d
e
r
B
e
h
a
v
i
o
u
r
e
n
g
i
n
e
:
:
T
r
i
g
g
e
r
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
A
I
F
l
y
i
n
g
P
a
t
r
o
l
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
H
e
l
i
c
o
p
t
e
r
M
o
v
e
m
e
n
t
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
T
a
n
k
I
n
t
e
n
t
i
o
n
B
e
h
a
v
i
o
u
r
T
a
n
k
A
i
m
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
P
o
i
s
o
n
R
e
a
c
t
i
o
n
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
V
e
h
i
c
l
e
B
e
h
a
v
i
o
u
r
A
m
b
i
e
n
t
p
r
o
t
o
:
:
A
u
t
o
T
a
r
g
e
t
i
n
g
B
e
h
a
v
i
o
u
r
T
a
g
B
e
h
a
v
i
o
u
r
e
n
g
i
n
e
:
:
R
a
g
d
o
l
l
L
O
D
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
D
e
c
a
l
B
e
h
a
v
i
o
u
r
e
n
g
i
n
e
:
:
A
d
v
e
r
t
i
s
e
m
e
n
t
B
e
h
a
v
i
o
u
r
e
n
g
i
n
e
:
:
N
I
S
P
l
a
y
e
r
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
L
i
g
h
t
D
e
c
a
l
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
M
i
s
s
i
l
e
J
B
e
h
a
v
i
o
u
r
T
h
r
e
a
t
B
a
l
l
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
Z
o
n
e
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
B
l
o
b
S
h
a
d
o
w
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
G
r
o
u
n
d
S
p
i
k
e
B
e
h
a
v
i
o
u
r
e
n
g
i
n
e
:
:
L
i
g
h
t
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
T
r
a
n
s
f
o
r
m
a
t
i
o
n
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
I
n
f
e
c
t
e
d
P
e
d
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
D
i
s
t
r
i
c
t
B
e
h
a
v
i
o
u
r
p
r
o
t
o
:
:
S
t
a
y
O
n
N
a
v
m
e
s
h
B
e
h
a
v
i
o
u
r
Implicit “Class Hierarchy”
Implicit “Class Hierarchy”
Summary
Designs change
Class hierarchies don’t like change
Components do, but not without
some sacrifices
Questions