Game development using Silverlight 2

Page 2 of 4
  1. Introduction
  2. The installation experience of a Silverlight application
  3. Writing a game loop
  4. Sprites

The installation experience of a Silverlight application

This article was originally published in VSJ, which is now part of Developer Fusion.

There are a couple things that you have to accept when you create Web-based games: users might not have the Silverlight plug-in installed; and users are impatient. Consequently, the very first time that they come to the page that is hosting your game, they might need to download and install Silverlight; and even if they have Silverlight already installed, they won’t want to wait long while a large application is downloaded. You should therefore perform at least two actions to make the experience a little more enjoyable for the user.

Tip #1: Improving the installation experience

One of the best ways of improving the installation experience is to display a background image in the <div> element that will be used to host the Silverlight control on the page. Typically, this will be an image of the final Silverlight application, plus possibly a message to indicate that the application requires Silverlight. Figure 1 shows a very crude example of how this might look for an application.

Figure 1: The installation experience

Figure 1: The installation experience

Achieving this effect typically involves tweaking a small amount of JavaScript to dynamically style the <div> element that is used to host your Silverlight control, based on whether Silverlight is installed or not. Fortunately, all of this has been covered in great detail elsewhere, so rather than regurgitate an already excellent document, I will instead urge you to look at the Silverlight Installation Experience Guide (October 2007).

This really is an essential read for developers creating any Silverlight application, and especially Web-based games, as it will show you how to minimise the friction between the Silverlight application and the rest of your Web site. So go download it now and then come back for the next tip.

Tip #2: Improving the application start-up time

So you’ve taken the trouble to create a large and exciting, multi-level game; it uses dozens of media files, graphic images and assemblies, all of which you package into Silverlight’s standard deployment package: a single .xap file. Unfortunately, the user will now have to wait until the entire set of content is downloaded to the client before the application will start, and that means that they will get a less than optimal user experience.

Where possible, therefore, you should separate your application into chunks that can be downloaded in the background. Let’s consider a small example application, SilverCommand, that emulates an old favourite arcade game of mine called Missile Command.

If you were to take a look in the .xap file for this application you would find that it only contains a single assembly. This initial loader assembly displays a simple (and fairly static) page of XAML that is shown in Figure 2.

Figure 2: Provide a splash screen

Figure 2: Provide a splash screen

What’s more interesting is the code behind the loader page:

public partial class LoaderPage :
    UserControl {
    public LoaderPage() {
    	InitializeComponent();
    	Loaded += OnLoaded;
    }
    private GameEngine gameEngine;
    void OnLoaded(object sender,
    	RoutedEventArgs e) {
    	WebClient wc = new WebClient();
    	wc.DownloadProgressChanged +=
    		OnDownloadProgressChanged;
    	wc.OpenReadCompleted +=
    		OnGameEngineDownloaded;
    	wc.OpenReadAsync(
    		new Uri( "SCGameEngine.dll",
    		UriKind.Relative ) );
    }
    void OnGameEngineDownloaded(object
    	sender, OpenReadCompletedEventArgs
    	e) {
    	if( e.Error != null ||
    		e.Cancelled ) {
    		DisplayErrorPage();
    		return;
    	}
    	AssemblyPart ap =
    		new AssemblyPart();
    	Assembly asm = ap.Load( e.Result );
    	foreach(Type t in asm.GetTypes()) {
    		if( t.GetCustomAttributes(
    			typeof( GameEngineAttribute ),
    				false ).Length == 1 ) {
    			gameEngine = (GameEngine)
    				Activator.CreateInstance(t);
    			HideProgressBar();
    			EnableStartButton();
    			break;
    		}
    	}
    }
    // These methods are elided for
    // brevity
    private void DisplayErrorPage() {...}
    void OnDownloadProgressChanged(
    	object sender,
    	DownloadProgressChangedEventArgs e)
    	{ ... }
    void HideProgresBar() { ... }
    void EnableStartButton() { ... }
}

The exciting part about this listing is that it begins an asynchronous download of the main game engine as soon as the initial loader page has been displayed to the user. They therefore get to see a nice progress bar (and perhaps interesting game information) very quickly – the compiled DLL for this is only 12KB, after all – whilst the main portions of the game’s code and assets are downloaded in the background.

As you can see from the listing above, the main portion of the game is downloaded using a standard WebClient object, which can be used to download any asset – including assemblies – from the site. Once the game engine assembly is downloaded, standard .NET reflection techniques are used to find and instantiate the type that is decorated with a custom attribute. I used this attribute to mark the object to which control should be passed at the appropriate time, which in this case when the user clicks the (now enabled) Start button.

Of course, you can refine this further, creating and parsing your own manifest files which indicate when and how assets should be downloaded. You could also use the IsolatedStorage APIs available in Silverlight to cache the content on the client.

The point of the tip, though, is that you should factor your application out into parts that easily allow you to get something onto the screen quickly, in order to retain the user’s interest.

Tip #3: The “ZIP XAP” tip

A .xap file is just a standard .zip file with a different extension. Therefore, if you want to take a look at the contents of a .xap file, simply rename it to have a .zip extension and peruse it using your favourite .zip editing program. At run-time, you can use the StreamResourceInfo class and the Application.GetResourceStream method to crack open a .zip file and read out a specific part, as shown in the small code snippet below that extracts the welcome.png image out of a downloaded .xap file:

Stream str = ...;
// get stream using WebClient downloader
// str refers to a MemoryStream
// containing the ZIP file
// Use StreamResourceInfo to enable
// access to the ZIP file's
// individual elements
StreamResourceInfo zipSRI = new
    StreamResourceInfo( str, null );
// Specify using a relative URI
// the item in the ZIP file
Uri imageUri = new Uri(
    "welcome.png", UriKind.Relative );
// Obtain a new StreamResourceInfo
// object to the image file itself
StreamResourceInfo imageSRI =
    Application.GetResourceStream(
    zipSRI, imageUri );
// Display the image in the
// Image control named bimg
BitmapImage bimg = new BitmapImage();
bimg.SetSource( imageSRI.Stream );

Tip #4: The “Click to Start” tip

I find that there is actually another fringe benefit of having an initial downloader page, such as that shown in Figure 2, which has a big “Click to Start” button on it: by forcing the user to click on the Silverlight control, you ensure that it gains focus. This helps avoid the frustration that can occur if the main input to the game is the keyboard, and some other element in the browser has retained focus. At this point, the Click handler for the button will also typically engage your main game engine, whatever that might be. And that’s where the next tip comes into play: running a game loop.

You might also like...

Comments

About the author

Dave Wheeler United Kingdom

Dave Wheeler is a freelance instructor and consultant who specialises in .NET application development. He’s a moderator on Microsoft’s ASP.NET and Silverlight forums and is a regular speaker at ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Debuggers don't remove bugs. They only show them in slow motion.”