Source code: http://www.bluerosegames.com/spacerocks/SpaceRocks_2_Sprites.zip
When we refer to a “sprite” in game development, we’re typically referring to any 2D visual element. Sometimes sprites are defined as only elements that can move but since any element in Silverlight can be moved by repositioning it, the definition still fits. In the Space Rocks game, the sprites will be the ship, asteroids, bullets, particles, and enemy ships.
These elements share some common needs including the following:
- Movement based on velocity
- Collision detection
- Ability to “wrap” when hits edges of screen
The common behaviors of sprites for your game really depends on the game itself and so it’s difficult to create a general purpose sprite class that meets all of your needs. Generally when starting a new game I grab a sprite class I’ve done before that’s closest to what I need and then tweak it for the current game. Odds are that the sprite class we create for this game won’t do exactly what you need but it can be a good starting point to create your own.
I’ve tried a few different techniques for creating a sprite class, but the one I’ve settled on is to use a templated control. Templated controls are nice for sprites because it’s easy to inherit from a base class while still making the sprite look however you want. It’s also easy to edit these templates in Expression Blend to design your sprites.
Let’s create a Silverlight Templated Control called Sprite.cs.
When you create this, the class is generated as follows:
using System.Windows.Controls;
namespace SpaceRocks
{
public class Sprite : Control
{
public Sprite()
{
this.DefaultStyleKey = typeof(Sprite);
}
}
}
The default style key is set to typeof(Sprite) and this corresponds to an entry in Themes/Generic.xaml. This entry looks like this:
<Style TargetType="local:Sprite">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Sprite">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can replace the contents of the ControlTemplate with whatever you want. Let’s just set a couple of properties on the Border so that we have a default sprite that can be displayed if we’re not inheriting it with a custom template.
<ControlTemplate TargetType="local:Sprite">
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" Width="50" Height="50" Background="Red"/>
</ControlTemplate>
This will display a 50×50 red square.So let’s see how we can add this sprite to our game control. The game control currently had a Grid as its root element. We don’t really need the layout features of a Grid for this game, so we can change the root element to a Canvas. You can also remove the TextBlock we used in the last sample, and make sure to remove the code from the GameLoop_Update method too. This is our new Game.xaml:
<UserControl x:Class="SpaceRocks.Game"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480"
xmlns:local="clr-namespace:SpaceRocks"
xmlns:silverSprite="clr-namespace:SilverArcade.SilverSprite;assembly=SilverArcade.SilverSprite.Core">
<UserControl.Resources>
<silverSprite:GameLoop x:Key="gameLoop" Update="GameLoop_Update" />
</UserControl.Resources>
<Canvas x:Name="LayoutRoot" Background="Black" Width="640" Height="480">
</Canvas>
</UserControl>
Now to add the sprite. You can add it in XAML, but many times in a game you want to have more control over when your sprites are displayed so let’s add it in code. In the Game constructor after the InitializeComponent() method we’ll create a sprite and add it to the canvas’ children:
using System;
using System.Windows.Controls;
namespace SpaceRocks
{
public partial class Game : UserControl
{
public Game()
{
InitializeComponent();
Sprite sprite = new Sprite();
LayoutRoot.Children.Add(sprite);
}
private void GameLoop_Update(object sender, SilverArcade.SilverSprite.SimpleEventArgs<TimeSpan> e)
{
}
}
}
And here is what it looks like when you run the game:
Pretty cool huh? Ok so that’s not very exciting. Let’s see what we can do about positioning this sprite. For elements on a Canvas, you can use the Canvas.Left and Canvas.Top attached properties to position them. To avoid doing GetValue and SetValue all over the place and also to only set the attached properties if something changed, we can add an X and Y property to our sprite class which will set these for us.
using System.Windows.Controls;
namespace SpaceRocks
{
public class Sprite : Control
{
double x, y;
public Sprite()
{
this.DefaultStyleKey = typeof(Sprite);
}
public double X
{
get
{
return x;
}
set
{
if (x != value)
{
x = value;
this.SetValue(Canvas.LeftProperty, x);
}
}
}
public double Y
{
get
{
return y;
}
set
{
if (y != value)
{
y = value;
this.SetValue(Canvas.TopProperty, y);
}
}
}
}
}
By storing off the x and y values we don’t need to call GetValue to get those properties if needed. Now if you add the following lines to the Game constructor:
sprite.X = 100;
sprite.Y = 50;
And run the game again you’ll see that the sprite is positioned according to our X and Y values.
