Slate Management in Silverlight

Written by:  • Edited by: Linda Richter
Updated Dec 15, 2009
• Related Guides: Adobe Flex | Silverlight

A Silverlight development tutorial that shows you how to create your own 2D games. This series attempts to recreate a game developed with Flash, and can be used to highlight the differences between the two platforms. This article shows you have to implement state management

In this article we will take a look at state management. The term “state management” can have two interpretations: one is managing the transitions between application states (for example main menu to game play to high score screen), and the other is the persistence of a state information across application executions. Even though the two terms don’t have much in common technically, we will cover both here.

The first concept we will explore is the persistence of state information between the executions of the Silverlight application. In a traditional web based application the state of the user session is either stored on the server (in a session state), or by way of cookies on the client. Both systems are used to compensate for the inherently stateless nature of a HTTP transaction. Silverlight is different in that all execution takes place on the client. In fact the Silverlight application doesn’t even need a server: it can be embedded in a local HTML document with no network access at all. In this respect a Silverlight application is more like a desktop application than a traditional web app. So without a server to save data onto how does a Silverlight save non-volatile data?

Silverlight has access to an IsolatedStorage class, which gives the developer the ability to save data that persists after the application has been terminated. This information is traditionally saved to the local hard disk, but the reality is that as developers we don’t need to know or care how the data has been saved. All we need to know that, if IsolatedStorage has not been disabled, we can save data that will be available next time the application is run.

We will make use of this ability to store the players score between games. The functionality will be implemented in the ApplicationManager SavedScore property.

ApplicationManager.cs C# Silverlight source code

Traditional .net developers will notice that this code looks very similar to retrieving data from an app.config file. IsolatedStorageSettings.ApplicationSettings presents a key/value dictionary that we can use to load and save persistent data. It’s worth noting that you can not assume that the IsolatedStorage contains your data, as the end user can delete the contents of the isolated storage at any time. This is why we do so many checks before returning any data.

It’s also not recommended that you store any sensitive data using IsolatedStorage. This is because, while not easily accessible, it can be modified or hacked by the end user. If the players current score was used as part of a global ranking system it’s entirely possible that a clever user could modify their local IsolatedStorage data to give themselves an inflated score. Encrypting the data, or sending it to a server you trust, would be the best solution for any sensitive data.

Despite these few caveats the IsolatedStorage class makes saving and retrieving persistent data quite simple.

The second aspect to state management is the transition from one logical state to another. In the Flex version of the game we made use of the built in state management functionality to have two functions called with every state: one when the state was entered, and another when it was left. By placing the initialisation and cleanup code in these functions we could transition between logical states. Silverlight doesn’t have the same ability built in, so we will create a class called StateManager to do the job for us.

StateManager.cs C# Silverlight source code

The idea is to maintain a collection of delegate pairs; one that is called when entering a state and one when it is exited. Some extra code has been written to ensure that if a state change is made during another state change, that the pairs of functions are called in a logical way i.e. an exit state function will always be called after it’s accompanying enter state function. Apart from that all we need to do is register delegate pairs to a state and then make a call to setState when we want to change the current state.

We make use of the state management to introduce a main menu which we can drop back to by pressing the escape key. Although it’s a simple touch, being able to manage states will allow us to easily move from the main menu to the game, and maybe then to a high score screen or an end of level video clip, and back to the main menu.

Check out the online demo, and download the source code from the Sourceforge SVN repository, or download an archive containing all the source code here.

Back to Silverlight Game Programming Tutorials

What You Need

flixel
click to enlarge
Create a Flash platform game with Flixel and Adobe Flex

This tutorial series steps you through the process of creating a simple platform game using the Flixel game engine and Adobe Flex.


Comments

Showing all 5 comments
 
Billg Dec 29, 2011 11:16 PM
RE: Slate Management in Silverlight
Your state management example is too complex for me to follow.  <br><br>Is there somehting more basic?  How and where to the virtual functions exist, and how are the game loops managing the state?<br><br>I can see in the class how they are changed, but what executes the change? presumeably some update loop with a line that somehow turns the state into a function that gets called.  Cant find it.
Matthew Casperson Dec 5, 2009 6:19 PM
RE: Slate Management in Silverlight
Some good points. Thanks for the feedback.

As for 1C - all requests for a state change are placed in the newStateChangeRequests collection. This collection is then emptied and the state change requests deal with in updateState. This means any state changes requested in this loop (maybe because an exit state delegate has requested a state change of it's own) does not change the order in which state changes are processed.

If you request a state change and stateChangeLocked is true, it must mean that the request will be added to the newStateChangeRequests collection, which is then added to the pendingStateChangeRequests collection by updateState once the current round of state changes have been addressed. The state change update loop then starts again.
joniba Dec 5, 2009 8:23 AM
state
Ah, forget the comment about the updateStates() method, I just didn't read carefully. But I think you would have been better off using a single Queue rather than two Lists, since it seems like that is actually what you're trying to do (i.e., run through a queue of actions).
joniba Dec 5, 2009 7:39 AM
comments
Hi Matthew, thanks for the great tutorial. There is some really great stuff in here.

I just want to make a few random comments/suggestions:

1. StateManager: Very elegant work.
A. You don't need the StateFunction delegate as there is already one in the framework, called Action.
B. It seems to me this class could be a lot more useful if it was not a singleton. That way any stateful object could use it to manage its states.
C. If I call setState() and stateChangeLocked is true, what happens to my state-change request? It seems to just get queued until another request is made. Maybe the end of the updateState() method should check if there are pending requests and, if so, call itself.

2. Casts: You're code has a lot of casting going on, especially:
(SilverlightGame.App.Current.RootVisual as Page)
You would improve performance by saving the casted member (Page), rather than casting each time.

3. ResourceHelper: Every call to GetBitmap() is actually calling Assembly.GetExecutingAssembly().FullName, which is a considerably heavy performance toll. And since the executing assembly never changes, it could be saved as a readonly static member:

private static readonly string executingAssemblyName;

static ResourceHelper()
{
executingAssemblyName = Assembly.GetExecutingAssembly().FullName;
executingAssemblyName = executingAssemblyName.Substring(0, executingAssemblyName.IndexOf(','));
}


Once again, thank you for this great tutorial. I'd love to see more from you!

Joni
Vincent Oct 19, 2009 8:14 AM
Error encountered after running the source code
Tried running your source code from SilvelightGame2 on VS2008. However encountered a NullReferenceException error on : rect.Width = width ( a new keyword should be used instead). Please help to resolve this issue as I am not good at C#.
Thanks!
Vincent
 
blog comments powered by Disqus
Email to a friend