Accessibility help

Developers guide to writing a simple Silverlight game

Miscellaneous issues and tips

I covered the significant issues I ran into, but I thought I'd use this section to touch on a few lesser problems and a few tips.

Screen Layout

For those that don't know xaml, by default, it increases the z-order as you go down the page. So if you want a fake dialog/canvas to appear above the rest of the page then you can position it further down the page. Of course you can just set the z-order ;)

Creating numbers in a non-standard font

Olop is a fun little game and so we felt the standard fonts just weren't quirky enough (although Hannah will hate me saying quirky). So I asked her to produce a set of numbers from 0-9, stacked on top of each other. This was a single number control. I then created a score control that contained four number controls. It was then fairly easy to expose a number property to the control which displayed the correct number.

Debugging

Silverlight isn't blessed with the best error messages and it can become frustrating. In my experience the majority of problems were from unsupported xaml where I'd tried to use a non-supported WPF element. These errors are typically raised very early in the life cycle, and usually originate from InitializeComponent. However, if you want to debug exactly where the problem is, this is my tip. Find the call to InitializeComponent in your .cs file and drill into it. Then remove/comment out the [System.Diagnostics.DebuggerNonUserCodeAttribute()] and set a breakpoint in the code. This way you can narrow down the element that is causing the problem.

Problems playing sounds

The first problem I had with playing sounds was attempting to play a .wav file. Silverlight wasn't exactly forthcoming with the error message but I quickly realised .wav just isn't supported. So I turned from trusty wav to even more trustworthy mp3, surly PCs and Macs alike love mp3s don't they? I created a little demo of a shot sound and the mp3 played hurray. Put the sound into the game and nothing. Odd. After some playing around the sound would, infrequently, play. Odd. Rapidly causing the sound to play seemed to work but none of this was useful to the game. Eventually I converted the mp3 to wma and everything worked fine. I then received confirmation from the forums (from none other than Bill Reiss) that there is a flaw with playing small mp3s. So my advice...use wma for small files.

Resources

In order to play sounds I needed to load the sound, duh. But where to load them from, and what to load them with (sounds like a track from Blur). I didn't want any network latency so I thought the best option was to pack the sounds into the xap file. I must confess I got a bit confused between the choices; Embedded Resource or Resource sir? Well it turns out that I needed neither of those, in fact I needed to set the sound files to Content and do not copy. I could then load the sound by;

MediaElement mediaElement = new MediaElement();

mediaElement.AutoPlay = false;

Uri resourceUri = new Uri(resourcePath, UriKind.Relative);

StreamResourceInfo resource = Application.GetResourceStream(resourceUri);

mediaElement.SetSource(resource.Stream);

this.gameSurface.Children.Add(mediaElement);


Persisting user information

One of the interesting features of Silverlight is its ability to persist information to the user local file store via Isolated Storage. Whilst not a new feature to Windows developers it certainly provides an easier persistence mechanism for browsers than cookies - plus converting to WPF is easy. I used Isolated Storage to store the user's high score (I'd love to use a High Score service but sometimes you just need to get something out there). Typically I use Xml to store settings data and I felt no reason to change here. However, Silverlight doesn't include the typical Xml classes so I turned to serialization to help me out. By using the DataContract attributes I decorated my Settings class to explain how and what I wanted to be persisted;

[DataContract]

public class Settings

{

   [DataMember]

   public double HighScore { get; set; }

 }

?

Once you have an object to serialize you need to get Silverlight to do the work;

...

using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())

{

   using (IsolatedStorageFileStream settingsFileStream =

     isolatedStorageFile.OpenFile("settings.xml", System.IO.FileMode.Create))

   {

     Type typeToSerialize = objectToSave.GetType();

     DataContractSerializer dataContractSerializer = new DataContractSerializer(typeToSerialize);

     dataContractSerializer.WriteObject(settingsFileStream, objectToSave);

   }

}

?

Once saved, you need to retrieve the values;

using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())

{

   if (isolatedStorageFile.FileExists("settings.xml"))

   {

     using (IsolatedStorageFileStream settingsFileStream =

       isolatedStorageFile.OpenFile("settings.xml", System.IO.FileMode.OpenOrCreate))

     {

       if (settingsFileStream.Length > 0)

       {

         DataContractSerializer dataContractSerializer = new DataContractSerializer(typeOfObjectToLoad);

         return dataContractSerializer.ReadObject(settingsFileStream);

...

The method did catch me out. Initially I used Create or Append which leaves the original settings file on disk and appends to it. The problem is that if the file gets smaller it leaves bits of Xml tags from the previous save in the file and Xml really doesn't like random tags floating around! So I switched to Create to ensure the file is purged before writing.

Tip: To check the contents of the isolated file set a breakpoint on the GetUserStoreForApplication code and it will tell you where the file is located on the disk. You can then navigate to the location and examine the file.

Problems with Xaml from Blend

One of the reasons for starting this project was to get first hand experience of the "new" workflow process for a developer and designer, I.e using Visual Studio and Blend with xaml as the common denominator. The first problem was the naming of elements. Blend makes it relatively easy to create lots of controls and paths, storyboards, etc. whilst still making it easy to navigate around the control tree which is great from a designers point view. However, once in Visual Studio all I get is chunk of semi-meaningless xaml with no way of associating a xaml element with the rather poor preview pane. So the first lesson we learnt was name the items in Blend even though this isn't strictly helpful to the Blend user, it's a must for the developer. Conversely sometimes Blend isn't that great at helping with problems in the xaml and it's particularly naughty at creating unnecessary elements. So there were a few occasions where we switched to xaml view in Blend to easily correct some problems. However, Blend lacks Visual Studio's xaml edit so you loose the ability to do the simple things, such as collapsing islands or ctrl+] to navigate to start/end of tags. Second lesson, use the xaml edit to correct flaws in Blend, and if there is a lot of work then do this in Visual Studio. The third lesson is for the developer to install Blend, sometimes you need it to navigate the xaml, but don't be tempted to edit using it, you're not a designer, you're not a designer.....Lesson four, the canvas offset. When you create controls in Blend you can happily ignore the root canvas. This can result in the developer getting a user control where the bulk of the graphics are at some huge offset to the root canvas. To avoid this always give the root canvas a default colour while developing the assets, that way you can immediately see what the offset will be.

Well that's all folks, hope you found this useful, and why not have a quick go at helping Olop save the ice. Paulio.

Play the game >>

<< Collision detection

numbers