The most difficult engineering challenge in Fireflies was dealing with
tombstoning. For those unfamiliar, tombstoning is Microsoft’s term for
what happens when your app is interrupted. An interruption might be, for
example, the user receiving a call, locking the screen, or hitting the home
button. As of the game’s publication, the phone did not have multitasking
support. Therefore, during an interruption, the app gets a notification that
it’s being tombstoned, then its process is terminated. This means that every
well-behaved app needs to expect these interruptions and be prepared to save
its state so it can resume the new process were the old left off.
To accomplish this, the game needs to be completely serializable no matter
which state it’s in. This turns out to be quite a daunting task to do
correctly. Many games in the Marketplace just punt entirely and only remember
basic things like your current level. Receive a phone call at the end of the
boss fight? I guess you get to start over! Just beat your old high score and
accidentally bumped the ad? Sucks for you!
This is, of course, unacceptable behavior. We were pedantic about making sure
the game can handle any interruption at any time, and the exact game state
will be saved, down to the positions of the little fireflies in the jar. As a
first step, we need to decide how to serialize the game state.
Some people roll their own serialization, typically with a custom interface,
perhaps something like IBinarySerializable. When performance is an issue,
this might be the necessary option, but it comes with several drawbacks.
Mainly, you spending time trying to debug why your objects are full of garbage
since your forgot to read in an int somewhere and screwed up the stream. If I
wanted to deal with that kind of crap I’d be writing in C. Thus, we chose to
avoid this on the grounds that I’d rather be making a game than figuring out
the best way to serialize reference cycles in my object graph. The good people
on the .NET team figured out all this hard stuff already.
For a small, simple game, the built-in methods are perfectly fine. The two
main options are XmlSerializer and DataContractSerializer. The differences
didn’t really matter for our simple case, but we went with
DataContractSerializer, since which members are serialized are opt-in rather
than opt-out. We didn’t want to accidentally serialize a RenderTarget2D or
other ephemeral resource.
Not that the built-in serializer doesn’t have its own drawbacks. In order to
serialize private and read-only members, the serializer must use unsafe code.
Only you can’t use unsafe code on the phone. So no private or read-only
members, I guess. Well, good thing we already wrote the game code. At least I
won’t have to cringe looking at it.

Of course it’s not enough to just write your entire program state to disk. An
important part in making serialization work smoothly is keeping the
persistent data (stuff you need to serialize) separate from the ephemeral
data (stuff you can re-create next time). For example, all of our assets such
as textures are loaded into one object, and no game state objects hold onto
any references to any assets. The asset-holding object is passed to every
update or render function that needs them. Now we don’t need to worry about
fixing up game state objects after deserializing them, since they don’t have
any references to ephemeral resources. This kind of separation is a good idea
anyway, but it’s absolutely crucial if you want to be able to quickly and
easily save the persistent data.
There’s also many special situations to consider. What happens if the user is
entering their name for a highscore in XNA’s built-in keyboard input control
when they hit the home button? Turns out the control returns the empty string
before the process exits, which left a blank name in the highscore list.
Therefore, the game has to check on startup if the name field for the most
recent score is empty and, if so, bring up the dialog again. What happens if
the game is tombstoned during first initialization? The game saves out an
uninitialized game state, then happily loads in said state next time and
crashes. So the game has to be careful to only save after initialization is
complete.
So, even with the built-in serialization, it still took over a week to get
saving and loading fully working. Solving corner cases took a lot of time, but
I’m really proud that our game handles them. Even when multitasking support
arrives, it’s still nice for the user to be able to back out of your app and
return later to find the app exactly as it was. So make sure to take care of
your users. They’ll be much happier for it.