Developers guide to writing a simple Silverlight game
Drawing sprites onto the screen
The fun stuff, actually drawing stuff onto the screen. Silverlight may not be a games engine but creating sprites is a breeze. The technique I used was to ask the graphic designer (Hannah Watkins from Clear Breeze Design) to create sprites as individual User Controls in Blend. Then the game can dynamically create (and maintain) the sprites as you would any user control. It's easy ;) Ok maybe it's not obvious so here's a cut down snippet from Olop.
Dynamically adding controls to the game surface
private void CreateCharacters(NonPlayerSprite[] characters, double top, double left, NonPlayerMovementMode nonPlayerMovementMode,
NonPlayerBombMode nonPlayerBombMode)
{
for (int characterCount = 0; characterCount < characters.Length; characterCount++)
{
NonPlayerSprite character = characters[characterCount];
this.nonPlayerCharacters.Add(character);
this.gameSurface.Children.Add(character);
}
}
The important part to remember is to always add the control (in this case 'character') to the control tree (this.gameSurface.Children.Add), otherwise you won't see anything! What I haven't shown is the code to create the control/sprite itself. This is because the game changes the characters depending upon the level, therefore I used a Factory pattern to deliver the user controls based upon the level the player has achieved.
Level factory
The pattern is pretty simple, pass in the level and the code returns the set of characters to display;
public static List<LevelCharacterSet> CharactersForLevel(int level)
{
List<LevelCharacterSet> characterSets = new List<LevelCharacterSet>();
?
Can[] cans = { new Can(), new Can(), new Can(), new Can(), new Can() };
LevelCharacterSet levelCharacterSet = new LevelCharacterSet(
cans, NonPlayerMovementMode.NoVerticalMovement, NonPlayerBombMode.None,
new Point(100, 30));
?
What I tried to do with the factory is find a way to return the characters in a generic way where the caller just deals with a LevelCharacterSet rather than needing some ugly set of ifs or a large switch statement. To aid in this I created a class hierarchy of;
User Control - > Sprite -> NonPlayerSprite
This created a practical problem with Visual Studio. When you create a user control Visual Studio creates a number of files for you; the .xaml and .cs are for you to edit but the .g.cs is generated to hold all the plumbing that you shouldn't be, or want to be, messing with. It provides this nice separation through the use of partial classes, however this is where the problem lies. For example, when I created the IceShard user control the .cs contained the following code;
public partial class IceShard : UserControl
However I want to deal with NonPlayerSprite not just User Control so I changed it to;
public partial class IceShard : NonPlayerSprite
Unfortunately Visual Studio isn't "watching" that closely, so when I compiled I got an error complaining that you can't have different base classes. The problem is with the hidden .g.cs file which still contains the code to derive from UserControl. But where is this pesky file? Well you can find it lurking under obj\<configuration>\<control filename>.g.cs. So in my case that was obj\Debug\IceShard.g.cs
To make life easy I kept the file open in Visual Studio as it's quite easy to make a change to the xaml and for Visual Studio to simply overwrite the code with UserControl again. I'm not sure if Microsoft have fixed this issue yet, but just in case they haven't just keep the file open and/or try to avoid accidentally poking the original xaml file.
That all sounds like effort so why not just stick with User Controls?
Sprite & NonPlayerSprite
Silverlight, and its WPF older brother, use xaml as the declarative language of choice. It's way beyond this little article to discuss the many merits of xaml but there are some parts I find annoying. One of these is accessing dependancy properties. For example, to make decisions about a character you must know some basic facts such as the position and size of the root canvas of the user control. Most xaml guidance recommend wrapping dependency properties with your own "standard" property. Now I could have written this position & size properties on each user control but they all share that code so why not go the base class route? However, not all sprites are the same. The monsters in the game all share properties about how they move, how they attack, etc. which are not relevant to other characters such as the player. Therefore, the NonPlayerSprite came into existence. So the advantages of having these single points of maintenance far out-way the niggling problems of changing the .g.cs files.
So we can create sprites (rather than just User Controls), add them to the control tree and handle keyboard input, but that doesn't make for a very interesting game.
