As both the author of Game Fabric and games using the platform, sometimes I might be a better platform developer than a game developer.
The GameFabric Action Service provides a mechanism to push down events to all the connected users in the game. These events then get picked up by your game UI and are used to update the visuals.
The GameFabric GameState Service provides a mechanism to capture game specific data and store it across all connected users.
This interaction can be thought of as a bucket full of water. Each action a player takes within the game adds a drop to the water in the bucket. Each action performed then gets dripped out of the bucket through a controlled down spout (the action service), allowing just one drop at a time out to be sent to multiple clients (the other players).
The water in the bucket, or the game state, represents a complete picture of the game. Each droplet, or action, represents one tiny step in the game’s history. These tiny steps can be used to update the user interface because they come with some context.
So what is the anatomy of an action? Well, its composed of three parts:
1. Player: who performed the action.
2. Verb: logical identifier to uniquely identify different types of actions
3. Parameters: collection of parameters to provide deeper insight into what the action should do.
The beauty of this approach is that, it doesn’t matter what your game is, you can use the action service to send the next event down to all your players’ phones. In Euchre, I designed 7 action verbs that my game client would handle. Pick, Call, Drop, Play, Match-Over, Round-Over, Game-Over. Each of these actions has some parameters that help my client determine what needs to be displayed to the user without going and grabbing a game state.
However, the way I originally wrote the Euchre client poorly leveraged this architecture. I added an 8th verb called ‘update-game-state’. This action was invoked after every other action and the client used this verb to simply call the game state service and download the latest game state. This made it simple to implement the client but did not make for great user experience.
Let me explain this anti-pattern in greater detail before I dig into why the approach sucked so bad.
Basically, I had a standard MVVM setup inside my game application. I registered with GameFabric to pull down events for the appropriate session but instead of handling the event feed, I lazily relied upon update-game-state to tell me when to go download the game state. I would download the entire game state, blow away the old game state, and update the UI entirely from the new game state. This is essentially, Save-Open-Save that we see in document-based applications.
A couple problems:
1. The UI was unresponsive during the game state loading and since the game state is updated very frequently this resulted in the graphics to appear jerky or sluggish to the user.
2. The communication was unnecessarily chatty. I used to see over 1000 actions in a single game session of Euchre. Now, Euchre averages about 300 actions. This significantly reduced the amount of usage I consumed of the cloud services that the platform is built on. And with my eCPM’s as low as they are, every little bit helps!
The platform was already doing the right things. I was getting distinguishable, parameterized actions for each action human or computer players made. However, my shoddy game logic within the Euchre Worker Role resulted in an 8th ‘update-game-state’ verb that caused all the problems. This anti-pattern verb became a crutch that I used to build the UI faster but not better.
I modified my Euchre Worker Role to only send absolutely necessary events. This means only meaty game related verbs needed to maintain context. I did not include any artificial verbs related solely to game functions like game state or UI cues. The latter, I avoided quite reluctantly as I briefly dabbled with the idea of using the action service to notify the UI of user input prompts. I decided against this approach for a variety of reasons (a topic I will reserve for a future post).
After I removed the crutch, my phone client now all but completely broken. I gutted the data bindings that drove many of the visuals and replaced them with imperative code that managed animations. I did keep some data bindings but only for text or other static content. All visual state changes or interactive elements were animated manually or using Visual State Manager.
It has been a lot of work, getting it right, and I still have a ways to go, but I am confident I am on the right path and my product both Euchre with Friends and Game Fabric will be leaps and bounds better than their previous versions.