Cartel is a ground-up city-building simulation game being built on SpatialOS by developer Bold Conjectures. Here, Lead Developer Zach Caceres is joined by Cheng-Han Chiang to talk about Global Game Managers in SpatialOS.
It won’t take long for a developer on SpatialOS to reach the inevitable question: how do I build my global game managers?
First, what’s a game manager? Managers assume important responsibilities for data management and state updates across a game’s entities and world. Managers are umbrella-like global objects, often written as singletons.
Before starting to port Cartel to SpatialOS, we relied heavily on managers to control almost all of our gameplay. AI Residents were generated and sent around the game world by a Resident Manager. Time and weather was run by, yep, a Time and Weather Manager. Most importantly, the economy of our game world was led by a Month Manager — a single entity that updated prices, conditions, and other states of constructible objects in Cartel’s game world.
If you have hundreds of buildings on screen and you need to sum their prices, choose a few to set on fire, or swap ownership from one player to another, having a single object with lists of network ids and other properties is a great way to get work done.
The Spatial Way
But since SpatialOS is a distributed system, designers can’t rely on Game Managers. Local variables won’t be synchronized across SpatialOS’s engines. Computation may occur at slightly different times. Life without game managers can seem a bit disorienting at first! But SpatialOS offers a solid alternative with some unexpected positive effects for Cartel.
You can think of Game Managers as ‘pushing’ states to game objects. In our case, the game manager would realize a certain time had passed and then ‘push’ state changes to our entities: buildings decayed and prices shifted. Then the manager computed various changes in the data and ‘pushed’ them to the UI and other visual aspects of the game world.
To get this effect in SpatialOS, we had to move our game manager functionality into the entities themselves. In SpatialOS entities are their own game manager. After updating their state, entities share their updated state with players and other entities as necessary. This is the big conceptual difference from how the average game designer thinks of their game manager.
Instead, you need to distribute game manager functionality to your entities.
Here’s how we did it for Cartel.
Instead of a global game timer, each building has its own timer that says every so often: ‘Time to update my state!’ The entity handles whatever computation it needs — in this case, calculating its profit or loss. Then it sends messages and events to notify the surrounding game world that its state has changed.
Notice, there is no ‘management’ at any point here: entities are updating themselves. Our UI and Player listeners are waiting for the entities to tell them when something has changed. This is almost the opposite of global game manager architecture because, from the player’s perspective, the game world is listening for entities to change themselves rather than the entities waiting for some umbrella object to change them.
Here’s a code snippet that shows how each entity performs the profit and loss calculations for a buildings and updates the rest of the world:
As the ProfitTimer reaches 0 the entity calculates profit or loss based on its own unique data and other variables, then passes that state change to a message and event. These update the player’s UI and the game world, which triggers a visualization and other effects.
You’ll notice a reference to ModifierManager. This is not a global game manager either — it’s a component that manages the area of effect that a building has on surrounding objects. As with the snippet above, the entity is calculating and managing its own area of effect and messaging other entities directly. No global game manager in sight.
Firing the Managers
There’s at least two benefits to tossing out global game managers.
First it’s much more scalable. Even modest game worlds in our initial UNET prototype would start to chug if too many changes had to occur in the game manager at once. We resorted to all sorts of clunky quick-fixes to get around the limitations, like staggering when streetlights turned on or sending some city residents back home in waves instead of all at once.
Second, our game world’s discrete ‘turns’ system felt weirdly artificial even though it was logical to get our state updates on a turn change.
After recreating this functionality in SpatialOS, entity profit and loss updates looked like this:
Since each entity is managing itself, the player receives information about revenue and losses in a staggered flow based on when the building was constructed.
For me, this didn’t harm the core dynamics of the game at all — because players are still receiving revenue in the time frames appropriate to their choices. However, now players receive rewards distributed in a less predictable pattern through time. Entities tick at their own rate. Players don’t stare at the UI waiting for the turn to change to get their cash. It just flows in and out as they act in the world. It feels better.
Follow our progress at www.cartelonlinegame.com.
Improbable is taking SpatialOS to GDC 2017. Check out our planned talks, events and booth.
Download SpatialOS and start experimenting with your own game development now!