A Data-Driven Game Object System: Scott Bilas Gas Powered Games
A Data-Driven Game Object System: Scott Bilas Gas Powered Games
GDC 2002
Scott Bilas Gas Powered Games
Introduction
Me
Scott Bilas Background System architect types Tired of fighting with statically typed systems for game code
You
Dungeon Siege >7300 unique object types (i.e. can be placed in the editor) >100000 objects placed in our two maps Continuous world means anything can load at any time
Cell Phones?
Definitions
Data-Driven
Meaning: No engineer required Engineers are slow Causes designers to hack around missing functionality Goal: remove C/C++ from game Line between engine and content is always moving
Definitions (Cont.)
Piece of logical interactive content Perform tasks like rendering, path finding, path following, speaking, animating, persisting Examples are trees, bushes, monsters, levers, waypoint markers, doors, heroes, inventory items Many are pure logic, never see them (triggers, elevator movers, camera sequences) Every game has these in some form
Definitions (Cont.)
Constructs and manages Gos Maps IDs to object pointers Routes messages Build from many things, but for this talk
Object
Missile
Spaceship
Explosion Asteroid
FriendFoeMissile
HeatSeekingMissile
EnemySpaceship
Object
Drawable
Collidable
Chewable
Missile
Spaceship
Asteroid
It Wont Work
There are hundreds of ways to decompose the Go system problem into classes
They are all wrong They dont start out wrong, of course Designer makes decisions independently of engineering type structures They will ask for things that cut right across engineering concerns
Requirements get fuzzier the closer your code gets to the content Will end up regularly refactoring Do not resist, will cause worse problems! However: C++ does not support this very well!!
Resists change over time Rearranging class tree requires lots of work
Class merging/hoisting (fights clean OOP) Virtual override madness Increased complexity increasing resistance Doc rot, editor out of sync
This is a database
(a very well understood problem) The data is important, nothing else matters
and were hard coding it every time To meet changing design needs, cant just data-drive the object properties, must datadrive structure (schema) of the objects
Each component is a self-contained piece of game logic Assemble components into Gos to build complete objects Specification for assembly driven by data Lay out data in a C++-style specialization tree to promote reuse and reduce memory usage Include and enforce an external schema
Two-Part Implementation
GoComponent
. . .
GoSkritComponent
Extension: Skrit
(DS Scripting Language)
Obvious requirement: build components out of skrit Leave high performance components in C++ Permits extremely fast prototyping
No rebuilds required Dont even have to restart game (reload on the fly)
Schema is internal
Simple implementation (assuming you already have event-driven scripting language ready)
GoSkritComponent derivative owns a skrit Override all virtuals and pass as events to skrit
Game and editor dont know/care difference between C++ and skrit components
21 C++ Components
actor, aspect, attack, body, common, conversation, defend, edit, fader, follower, gizmo, gold, gui, inventory, magic, mind, party, physics, placement, potion, store
INI file, config file, XML store, RIFF, all the same Permits generic data retrieval/storage DS has gas, think INI with nesting + goodies^2 Many books/articles on this Probably need one for other parts of the game anyway (i.e. youll find uses for it no problem)
Ref-Counted Impl
Contains / Owns
Component2 Component3
Field2 Field3
Raw Data
. . .
FuelHandle source GoDataTemplate* base
. . .
TableSpec* schema (shared) Skrit* object (Optional)
Contains / Owns
Field2 Field3
. . .
string name, docs
Compile ContentDb
Part 1: Build Schema
1. 2.
Compile ContentDb
Part 2: Build Templates
2. 3.
Open data handles to each template Keep track of root nodes, build specialization tree
base_chicken
chicken_red
chicken_grey
chicken_white
[t:template,n:chicken_white] { category_name = "1W_ambients"; doc = "chicken_white"; specializes = base_chicken; [aspect] { [textures] { 0=b_c_na_ckn_white; } } [common] { [template_triggers] { [*] { action* = call_sfx_script("feathers_flap_white"); condition* = receive_world_message("we_anim_sfx",1); } } } [physics] { break_effect = feathers_white; explode_when_killed = true; } }
Compile ContentDb
Part 3: Compile Templates
1. 2.
3.
Recursively compile templates root-down Add data components on demand Read in values, override base template fields This is all similar to C++ base-first member initialization in ctors.
Compile ContentDb
Special notes
Depends on how frequently you construct objects and how fast your data override system is Also permits special const-read optimization that can eliminate memory usage and CPU for variables that are never changed
Copy data components on write to avoid unnecessary memory usage If have many templates, will need to JIT compile leaf templates to save memory
Editor Integration
This is almost trivial Editor should have a property sheet type thing
This is a one-entry view into the db Map types and names onto fields using schema Can un-override easily by querying template Be sure to add a column or tooltip for docs!
Transforms data between game object and editor Supports cheap rollback (undo) by double buffering Does not exist in game, only needed in editor Automates saving all game object instances just compare vs. the const data and write out if different
Loading Objects
In DS, objects are referenced by content ID Look up instance block to get template to use Instantiate Go by that template
For each block in instance, create a new data component Specialize that data component from base in template Finally iterate through GoComponents and xfer in data to set initial values
Can be done with little regard for other components (just add it) Derive from GoComponent only
Add new block to C++ components schema (DOC IT) Use a factory method
Wait a second, wouldnt it be better to write using the scripting language? (Probably)
Same as C++, just stick it in there Everything should be autodetect here Extend the scripting language with metadata
Pass it straight through to schema query Can implement flags, docs, and custom game features like server only components etc.
Can be maintained by nearly anyone once its set up Should have multiple roots for broad types Try to avoid data duplication Reserve one branch for test templates
Mark it dev-only (so is excluded for retail build) Prefix with test_ or dev_ to avoid namespace pollution DS ended up with 150 or so
Direct and automatic editor support Designers can construct their own types to place in the editor (careful, monitor this!) By only saving out modified data in instances, can make global changes easily by modifying templates Reorganizing the template tree is easy If embed a sub-tree for designers to build custom views into the database
Some Pitfalls
Operations can end up being order-dependent, though this is more easily controlled Nothing here is unique to components DS has >7300 of them, many auto-generated System was designed for <100 Need to keep close eye on template complexity to avoid memory/CPU hog (i.e. unnecessary components or wacky specialization)
Future
Schema extensible Add flags and constraints that editor can use
Contact Info
Scott Bilas
http://scottbilas.com