1. Problem
You need to stop your XNA game when tombstoning occurs on your phone, by showing the game in pause mode.
2. Solution
You can use both the OnActivated and OnDeactivated event handlers provided by the Game class.
3. How It Works
Everything you studied in the previous recipes on tombstoning, including State collection, is valid for XNA games too. The big difference is the events raised when the application is tombstoned.
An XNA game responds to the OnActivated event when the application is either run or resumed from tombstoning. The game responds to the OnDeactivated event when the application is either tombstoned or closed.
NOTE
The Game class provides the OnExiting event handler, which is used to know when the application is going to be closed. The OnDeactivated event will be called after OnExiting as well. So in the OnDeactivated event handler, there is no immediate way to know whether the application is going to be closed or it has been tombstoned.
When the game is tombstoned, the application stores game settings in the State
dictionary. When the application is resumed from tombstoning, it loads
the game settings and shows a bitmap representing the game in pause
mode. Now if the user taps the screen, the game restarts.
4. The Code
To demonstrate
tombstoning management in an XNA application, we have created a bouncing
ball game that is paused if the tombstone occurs. The game provides a
pause mode screenshot that is shown after the game is resumed from
tombstoning.
The GameSettings
class contains three properties to store the ball location, the ball
velocity, and a Boolean indicating whether the game is in pause mode
(its value is true) or not (its value is false).
public class GameSettings
{
public bool Paused { get; set; }
public Vector2 Location { get; set; }
public Vector2 Velocity { get; set; }
public GameSettings()
{
Paused = false;
Location = Vector2.Zero;
Velocity = new Vector2(1f, 1f);
}
}
The GameSettingsManager class contains the Load and Save methods, which are used to load game settings from the State dictionary and to save them, respectively. With the Save method, the GameSettings object is stored in the GameSettings key of the State dictionary. With the Load method, we check whether the State dictionary contains the GameSettings key. If it does, the GameSettings object is loaded with the one provided by the State dictionary; otherwise, a brand new object is returned.
NOTE
The Visual Studio 2010 XNA game project doesn't contain the assemblies needed to use the State dictionary, so you have to add a reference to Microsoft.Phone and System.Windows DLLs.
public class GameSettingsManager
{
public static void Save(GameSettings settings)
{
PhoneApplicationService.Current.State["GameSettings"] = settings;
}
public static GameSettings Load()
{
GameSettings settings = new GameSettings();
if (PhoneApplicationService.Current.State.ContainsKey("GameSettings"))
settings = PhoneApplicationService.Current.State["GameSettings"] as
GameSettings;
return settings;
}
}
The Game1.cs file contains the OnActivated and OnDeactivated event handlers. In the former event handler, the Load static method from the GameSettingsManager class is called, and local variables' values are replaced with the stored ones. In the latter event handler, the Save static method is called, providing local variables' values and setting the Paused property to true.protected override void OnActivated(object sender, EventArgs args)
{
settings = GameSettingsManager.Load();
spriteLocation = settings.Location;
spriteVelocity = settings.Velocity;
base.OnActivated(sender, args);
}
protected override void OnDeactivated(object sender, EventArgs args)
{
settings.Paused = true;
settings.Location = spriteLocation;
settings.Velocity = spriteVelocity;
GameSettingsManager.Save(settings);
base.OnDeactivated(sender, args);
}
The Update method is
the core of the game, where all the logic is calculated, sprite
positions are updated, and in this case, the pause mode is checked. When
the game is in pause mode, the ball position is not changed and the
ball texture is replaced with the Game Paused bitmap. Then the code
waits for gesture events—specifically, for a tap on the screen—and when
it occurs, the Paused property is set to false and the game restarts .
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
if (settings.Paused == false)
{
spriteLocation = spriteLocation + spriteVelocity;
spriteTexture = ballTexture;
}
else
{
spriteLocation = Vector2.Zero;
spriteTexture = pauseScreen;
while (TouchPanel.IsGestureAvailable)
{
GestureSample gs = TouchPanel.ReadGesture();
switch (gs.GestureType)
{
case GestureType.Tap:
settings.Paused = false;
spriteLocation = settings.Location;
spriteVelocity = settings.Velocity;
spriteTexture = ballTexture;
break;
}
}
}
. . .
5. Usage
From Visual Studio 2010,
select Windows Phone 7 Emulator as the output target and run the
application. After few seconds, the emulator will show a bouncing ball
moving on the screen (see Figure 1).
Press the hardware Start
button, causing tombstoning. Now press the hardware Back button so that
the game is resumed. The application shows the Game Paused bitmap and
waits for a tap on the screen (see Figure 2).