I realized that I’ve given several people recommendations on how to deal with resuming a game from tombstoning on Windows Phone 7 over Twitter in the past month or so. So I figured I would write up my thoughts on it.
There is no perfect and objectively correct solution. But there are certain common sense things that I believe will help make every gamer’s experience great.
First: Read these: http://msdn.microsoft.com/en-us/library/ff817008(VS.92).aspx; and http://create.msdn.com/en-US/education/catalog/article/tombstoning_wp7_games. The second link especially but not until you’ve read the first one, since the first link sets out the Windows Phone 7 execution model and then the second link helps both clarify it and explain how an XNA game’s life cycle fits within and, at times, diverges from the Silverlight model. The remainder of my recommendations should match up with these guidelines, but I wrote them prior to re-reviewing the above so there may be some differences. If you spot any conflicts, please let me know so that I can revise this appropriately.
Second: Save as much state as possible. Do everything you possibly can to save everything (that matters). It’s harder to write by-hand BinaryWriter/BinaryReader serialization than to do simple XmlSerializer- or DataContractSerializer-based automatic serialization. But it’s not a lot harder and it will be faster and give you complete control over what gets saved and what gets tossed. If you need to shave some time off of your recovery and restore times, I definitely recommend a BinaryWriter/BinaryReader solution over dropping game state data. See the bottom for a BinaryWriter/BinaryReader sample.
You want to save as much game state data as possible for one simple reason: players won’t hate your game. On phone models where the Start button (aka the Home button/Windows button), the Search button, or both are on the touch screen itself rather than being hardware buttons, it is unfortunately too easy for users sliding their fingers quickly around the touch screen to accidentally slide over one of those buttons and send the game off to tombstoning.
(If I had any one wish that I could get phone manufacturers to grant, it would be to put a thin plastic lip across the screen to section off the main touch screen area from touch screen-based Start and Search buttons. Not much of one; just enough to prevent that accidental slide of a finger over an screen-based button. Your customers and developers will thank you profusely. Well, in truth they probably won’t thank you as they likely won’t realize how awesome it is that you thought to put that little strip there that provides them with tactile feedback to tell them their finger has reached the edge of the main screen area. But they won’t be silently grumbling about mistakenly hitting a button on their otherwise awesome phone, which will lead to them recommending their phone to friends and getting a new phone from you when that time comes!)
Third: You should (almost) always start at a splash screen on launch and return to a splash screen on restoring from tombstoning. When a player navigates to your game, they shouldn’t be greeted with a blank screen that lasts for more than a second. If the screen stays blank, then as the seconds tick by, they will begin to think your game is broken or has frozen up their phone. Angry players leave bad reviews (terrible for paid games) and never play your game again (terrible for ad-based free games). Implement a splash screen, go to that instantly, and proceed from there to your menu (or to the game if you decide to try to restore from tombstoning directly to the game; but note the caution below).
Fourth: Be wary of trying to return players directly to the game when restoring from tombstoning. Games, particularly games with a lot of assets, take a long time to load. Don’t assume that you can return the player right back to the game within the time limit before the system’s frozen process killer comes along and terminates it (I believe it’s ten seconds but have not been able to locate the precise time in my searching).
Fifth: If you do want to return the player directly to the game, do your loading on a background thread, display some kind of loading screen that animates in some way (to let the player know something’s happening) and have the main game thread responsive to input (specifically the back button so that a player who has changed his or her mind or returned accidentally can exit).
Sixth: However you return the player to the game, whether directly with background loading and an animated load screen or to the main menu with a “Resume Game” menu item as the first menu item, make sure to set the game to be paused if time is an element, if the player can die, or if any other bad consequence can come from the player being suddenly thrown into the game. Players won’t know when the game will finish loading and might be looking away when it does. Don’t make them hate you by launching them directly into the game with no notice and no chance to prepare.
Seventh: If the player can die, you should implement a short (3 second) count-down timer in the game whenever the player returns from the pause screen. This gives him or her a chance to see the game screen again, move their finger to the right place (assuming touch input) or try to tilt the phone correctly (assuming accelerometer input).
Eighth: Try to outwit your players. Many people love to try to find ways to outwit a game. Let’s say you have a game with checkpoints with the goal being to get as far as possible without dying. Imagine rather than saving the player’s exact position when they exit the game, you just return them to the last checkpoint. You’ve just introduced a loophole. Anytime a player is about to die, they’ll mash on the search button or the start button and, if lucky, return to the game at the last checkpoint with no life lost. If you implement online scoreboards, people who play without any such hunting for loopholes will score lower and probably enjoy the game less. So try to eliminate as many such things as you can think of early on.
The more popular your game gets, the more interested people will be in trying to cheat the system. You’ll need to get more creative then, of course. But there’s no point in over-engineering the game at the outset. Spend that time making the game better and worry about the problems of success when they come. But remember that a good resume experience is really important. The first time a player resumes your game could well be the last time they ever play it if they find out that the 15-20 minutes (or more) they had spent playing and making progress are gone forever either because you didn’t save their progress or because you launched them right back into the game and they die before even having a chance to orient themselves again.
Because I like including code samples where possible, I wrote up a quick sample of how to use BinaryReader and BinaryWriter to save data. The classes in question are examples only, but are heavily commented and illustrate how I go about using BinaryReader and BinaryWriter without including any extra clutter in terms of unrelated methods or properties that you might otherwise want in your actual classes and structs: http://bobtacoindustries.com/developers/utils/BinaryReaderWriterSample.cs.txt. As always, let me know if you have any questions, and please leave comments about anything you think developers should do or consider doing when dealing with resuming a game (whether WP7-specific or just for games in general).