Deprecated: Assigning the return value of new by reference is deprecated in /home/dieajax/public_html/wordpress/wp-includes/cache.php on line 36

Deprecated: Assigning the return value of new by reference is deprecated in /home/dieajax/public_html/wordpress/wp-includes/query.php on line 21

Deprecated: Assigning the return value of new by reference is deprecated in /home/dieajax/public_html/wordpress/wp-includes/theme.php on line 507
10 Minute Silverlight Game Programming Tutorial - Shootorial Conversion #3 (C#) : Die, AJAX!

10 Minute Silverlight Game Programming Tutorial - Shootorial Conversion #3 (C#)

Welcome back! In my previous Silverlight game programming tutorial, I converted Kongregate’s Flash Shootorial #2 to Silverlight, giving a scrolling background for the space ship to fly over. So today, in Shootorial #3, you will arm that ship with missiles, transforming into a lethal killing machine.

Kinda ;).

Again, keep in mind that Kongregate wrote these tutorials for beginning programmers, thus they prefered to “make things work” rather than “make things work in the best way”. And, in the interest of keeping the code simple, I plan to cut corners, too ;). Additionally, this tutorial builds on my other tutorials, so if you don’t understand something please refer to Shootorial Conversion #2 and Shootorial Conversion #1.

Here we go!

Prerequisites

QuickStart

If you want to see the end result of this tutorial and you have installed all the prerequisites, then please download the ZIP file below, unzip it and open the shootorial.html file in your browser. You can now press the spacebar and make your ship fire bullets. Like before, you will need to click on the Silverlight control to give it focus first.

You can also see it in action, here.

Lesson

Step 1: Go OO

To keep things simple, I avoided introducing too many object-oriented concepts into these tutorials. Kongregate went OO from the very beginning partially due to the need to subclass Flash’s MovieClip class, thereby gaining access to the onEnterFrame function. Since Silverlight only has one CompositionTarget.Rendering event, making subclassing unnecessary, so I avoided the added complexity of using objects to represent game entites. While this worked fine for a single ship, tracking multiple types of game entities flying across the screen requires much more per-entity state management. Thus, starting now, I will use classes to represent game entities.

First, however, we need to make an interface. Create a file named “IGameEntity.cs” and put this code in there:


namespace ShootorialApplication
{
  using System;
  using System.Windows;
  using System.Windows.Controls;
 
  public enum Direction { Left, Right, Up, Down };
 
  public interface IGameEntity
  {
    //Called once per frame
    void Update( Canvas theCanvas );
    void Move( Direction direction );
  }  
}

Think of IGameEntity as something akin to Flash’s MovieClip, except tremendously, less functional and only specifying behavior, not holding state.

Okay, so it’s nothing like MovieClip :).

Anyway, every class that represents a game entity will implement this interface. Similar to MovieClip’s onEnterFrame function, this interface has an Update function that gets called once per frame. Passing in the Canvas to this function allows a game entity to update the display when necessary. It also has a move function that takes a direction as defined by the Direction enum at the top of the file.

Step 2: Add a missle class

This version of the missle class will contain a bit more code then Kongregate’s version, so let’s start small. Create a file named “Missle.cs” and put this code in it:


namespace ShootorialApplication
{
  using System;
  using System.Windows;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Controls;
  using System.Windows.Shapes;
 
  public class Missle : ContentControl, IGameEntity
  {
    public Missle()
    {
    }
  }
}

Note, the Missle class derives from a ContentControl. A ContentControl, like any other “control” (in the classic sense), can receive input, has a Width and Height, displays a Background, etc. but can only display one piece of arbitrary content. This fits our requirements perfectly, since we only need to display a single picture of a missle. Also, being a ContentControl means we can add this game entity directly to the main canvas for immediate display.

In step 4 of Kongregate’s Shootorial #3, rather than use a pre-drawn image, Kongregate has the developer draw their own missle using the Flash IDE. Being sans any IDE, creating the picture of a missle in code will have to suffice. We could define a missle entirely in XAML, but since Missles get added and removed on-the-fly at runtime, simply adding it as a child element of the Canvas in the XAML will not work. That would only make it display on load. I’ll leave it up to an exercise for the reader if you want to go down that route, but in the mean time:


namespace ShootorialApplication
{
  using System;
  using System.Windows;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Controls;
  using System.Windows.Shapes;
 
  public class Missle : ContentControl, IGameEntity
  {
    public Missle(double left, double top)
    {
      Rectangle missleRectangle = new Rectangle();
 
      missleRectangle.Height = 7;
      missleRectangle.Width = 15;
      missleRectangle.Fill = new SolidColorBrush(Colors.White);
      missleRectangle.Stroke = new SolidColorBrush(Colors.Black);
      missleRectangle.RadiusX = 3;
      missleRectangle.RadiusY = 3;
      missleRectangle.StrokeThickness = 2;
 
      this.Content = missleRectangle;
 
      Canvas.SetLeft(this, left);
      Canvas.SetTop(this, top);
    }
  }
}

So, the constructor creates a Rectangle and sets the necessary attributes to make it look like the one in Kongregate’s tutorial and then, assigns it to the Content property (remember how we said that ContentControls hold a single arbitrary piece of content? There it is.). The constructor also takes in position parameters, since its initial position will depend on the position of the hero ship’s nose.

Continuing on, according to Kongregrate’s tutorial, missles from the hero ship fly to the right at a speed of 20 units per frame. Luckily, IGameEntity defines both movement and per frame update functions:


namespace ShootorialApplication
{
  using System;
  using System.Windows;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Controls;
  using System.Windows.Shapes;
 
  public class Missle : ContentControl, IGameEntity
  {
    private int speed = 20;
 
    public Missle(double left, double top)
    {
      Rectangle missleRectangle = new Rectangle();
 
      missleRectangle.Height = 7;
      missleRectangle.Width = 15;
      missleRectangle.Fill = new SolidColorBrush(Colors.White);
      missleRectangle.Stroke = new SolidColorBrush(Colors.Black);
      missleRectangle.RadiusX = 3;
      missleRectangle.RadiusY = 3;
      missleRectangle.StrokeThickness = 2;
 
      this.Content = missleRectangle;
 
      Canvas.SetLeft(this, left);
      Canvas.SetTop(this, top);
    }
 
    public void Update( Canvas theCanvas )
    {
      Move(Direction.Right);
 
      if( Canvas.GetLeft(this) > 640 )
      {
        theCanvas.Children.Remove(this);
      }
    }
 
    public void Move( Direction direction )
    {
      Canvas.SetLeft(this, Canvas.GetLeft(this) + speed);
    }

  }
}

Starting from the bottom, the Move function uses the now familiar SetLeft static function to increase the left coordinate by an amount defined by the speed variable. It ignores the direction, for now. The Update function calls Move, and then tests to see if the missle has left the bounds of the screen. If so, it removes the missle from the Canvas object’s Children property so it no longer gets updated or displayed. We can add and remove Missles directly to and from the Canvas object because they derive from ContentControl.

Whew, Missle class created. Now, let’s migrate the other game entities into classes. To make things easy, we’ll start with the background.

Step 3: Create a ScrollingBackground class

Keeping in mind the lessons we learned from creating the Missle class, creating a class for the backgorund shouldn’t pose any problems. Create a file named “ScrollingBackground.cs” and put this code in it:


namespace ShootorialApplication
{
  using System;
  using System.Windows;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Controls;
  using System.Windows.Shapes;
 
  public class ScrollingBackground : ContentControl, IGameEntity
  {
    public ScrollingBackground()
    {
    }
 
    public void Update(Canvas theCanvas)
    {
      Move(Direction.Left);
    }
 
    public void Move( Direction direction )
    {
      Canvas.SetLeft(this, Canvas.GetLeft(this) - 1);
 
      if( Canvas.GetLeft(this) < -2110 )
        Canvas.SetLeft(this, 0);      
    }
  }
}

Similar to a Missle, the Update function simply calls the Move function. As explained in the last tutorial, The Move function moves the entire background one unit to the left, until it ends and then resets back to 0. If this looks familar, it should because I cut it right out of theShootorialControl_Rendering event handler and pasted it right here. Later on, you will see what the new event handler looks like.

Now, let’s create a class for the hero ship.

Step 4: Create a Ship class

The class for the hero ship, to be stored in a file named “Ship.cs”, should now look pretty familiar:


namespace ShootorialApplication
{
  using System;
  using System.Windows;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Controls;
  using System.Windows.Shapes;
 
  public class Ship : ContentControl, IGameEntity
  {
    private int velocity = 10;
 
    public Ship()
    {
    }
 
    public void Update(Canvas theCanvas)
    {
    }
 
    public void Fire(Canvas theCanvas)
    {
      Missle missle = new Missle(Canvas.GetLeft(this) + 57, Canvas.GetTop(this) + 17);
 
      theCanvas.Children.Add(missle);
    }

 
    public void Move( Direction direction )
    {
      if( direction == Direction.Right )
        Canvas.SetLeft(this, Canvas.GetLeft(this) + velocity);
      else if( direction == Direction.Left )
        Canvas.SetLeft(this, Canvas.GetLeft(this) - velocity);
      else if( direction == Direction.Up )
        Canvas.SetTop(this, Canvas.GetTop(this) - velocity);
      else if( direction == Direction.Down )
        Canvas.SetTop(this,Canvas.GetTop(this) + velocity);
    }
  }
}

I highlited the Fire function since no other class defines one, thus far. This function puts the Missle class to use by creating a new Missle and positioning it at approximately the nose of the ship. Then, it adds the Missle control to the Canvas object’s Children property for display. Remember because we derive Missle from ContentControl, we can add it directly to the Canvas like this.

Moving on, this time, the Move function will make use of the direction variable. Again, I cut this code from the ShootorialControl_Rendering event handler, modified it slightly, and then pasted it here. Originally, that code looked the Key property of the KeyEventArgs class to determine which direction to move the ship. This code simply checks a value of type Direction, and then proceeds to do the same thing as before. No real magic. I also highlighted the velocity variable to remind the reader that this too migrated out of the ShootorialControl class.

Speaking of the ShootorialControl class, it looks like we’ve pretty much stripped it bare of functionality. Let’s see what we can do about that.

Step 5: OO enable the ShootorialControl

Before touching the C# code, the XAML needs a slight modification: both the background and ship objects represent ContentControls not Images, so we need to update the XAML accordingly:


<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:shootorial="clr-namespace:ShootorialApplication;assembly=ShootorialApplication"
  x:Class="ShootorialApplication.ShootorialControl">
  <Canvas x:Name="theCanvas" Width="640" Height="300">
    <shootorial:ScrollingBackground x:Name="background" Canvas.Left="0" Canvas.Top="0">
      <Image Source="/scrollingBackground.jpg" />
    </shootorial:ScrollingBackground>

    <shootorial:Ship x:Name="spaceShip" Canvas.Left="281" Canvas.Top="132">
      <Image Source="/ship.png" />
    </shootorial:Ship>

  </Canvas>
</UserControl>

Yeah, I know I got some ’splain’ to do ;). First, the shootorial namespace definition uses the “clr-namespace” syntax, making the types defined in the ShootorialApplication assembly available to the XAML compiler. Prefixing elements with that namespace allows instantiation of user-defined types in XAML, just like any regular Silverlight UI object. So below, you can see that both a ScrollingBackground and Ship get instantiated as children of the Canvas very similar to the Images there previously. Also, note that both the ScrollingBackground and Ship objects contain Image objects as children. Being ContentControls, when they do this, the Image gets automatically set as the Content property, similar to how Missle constructor set the Content property to a Rectangle in Step 2.

With the XAML out of the way, let’s move onto the key down event handler. You’ll note that the Ship class does not directly handle key events in its Move function, only direction. So, the ShootorialControl class will translate key presses into directions:


...
private void ShootorialControl_KeyDown(object sender, KeyEventArgs e)
{
  if( e.Key == Key.Right )
    spaceShip.Move( Direction.Right );
  else if( e.Key == Key.Left )
    spaceShip.Move( Direction.Left );
  else if( e.Key == Key.Up )
    spaceShip.Move( Direction.Up );
  else if( e.Key == Key.Down )
    spaceShip.Move( Direction.Down );
}
...

That shouldn’t need much explaination. But, what about firing missles? Since pressing the space bar shoots missles, this function needs an if statment to handle a space bar key press:


...
private void ShootorialControl_KeyDown(object sender, KeyEventArgs e)
{
  if( e.Key == Key.Right )
    spaceShip.Move( Direction.Right );
  else if( e.Key == Key.Left )
    spaceShip.Move( Direction.Left );
  else if( e.Key == Key.Up )
    spaceShip.Move( Direction.Up );
  else if( e.Key == Key.Down )
    spaceShip.Move( Direction.Down );
  else if( e.Key == Key.Space )
    spaceShip.Fire(theCanvas);

}
...

Simple enough, except for one problem: doing it this way would allow lots of missles to build up and fire, potentially one per frame. To prevent this chaotic effect, in step 9 of Shootorial #3, Kongregate adds what they call a “shoot limiter”, which only allows missles to fire once every eight frames, sort of like this:


private int shootLimiter = 0;
...
private void ShootorialControl_KeyDown(object sender, KeyEventArgs e)
{
  if( e.Key == Key.Right )
    spaceShip.Move( Direction.Right );
  else if( e.Key == Key.Left )
    spaceShip.Move( Direction.Left );
  else if( e.Key == Key.Up )
    spaceShip.Move( Direction.Up );
  else if( e.Key == Key.Down )
    spaceShip.Move( Direction.Down );
  else if( e.Key == Key.Space && shootLimiter == 8 )
  {
    shootLimiter = 0;
    spaceShip.Fire(theCanvas);
  }

}
...

We declare a new variable named “shootLimiter” and everytime it reaches the value of 8, the player can fire a new missle. Note that firing a missle also resets the “shootLimiter” forcing the player to wait at least another 8 frames before they can fire again.

Since the “shootLimiter” variable gets incremented once per frame, then that needs to happen in the ShootorialControl_Rendering event handler, which gets called once per frame:


...
private void ShootorialControl_Rendering(object sender, EventArgs e)
{
  if( shootLimiter < 8 )
    shootLimiter += 1;
}
...

This function needs to handle one more piece of per frame functionality. As defined in step 1, each IGameEntity instances Update function needs calling once per frame. Every IGameEntity instance lives in the Children property of the Canvas so, a simple for loop should do the trick:


...
private void ShootorialControl_Rendering(object sender, EventArgs e)
{
  if( shootLimiter < 8 )
    shootLimiter += 1;
 
  for( int elementIndex = 0; elementIndex < theCanvas.Children.Count; elementIndex++ )
  {
    IGameEntity gameObject = theCanvas.Children[elementIndex] as IGameEntity;
 
    if( gameObject != null )
    {
      gameObject.Update( theCanvas );
    }
  }

}
...

Nothing terribly difficult going on here. The for loop tests element of the Children collection to see if it derives from IGameEntity and if so, calls the Update function passing a reference to the Canvas as a parameter.

Whew, that’s it! Time to build this sucker!

Step 6: Build it

Luckily, the build file doesn’t need much work. It just needs another ItemGroup that references the new class files:


...
<ItemGroup>
  <Compile Include="IGameEntity.cs">
  </Compile>
  <Compile Include="Missle.cs">
  </Compile>
  <Compile Include="Ship.cs">
  </Compile>
  <Compile Include="ScrollingBackground.cs">
  </Compile>
</ItemGroup>
...

You can build this with the usual command line:


"C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" ShootorialApplication.csproj
Step 7: Run it!

To run it, simply open the shootorial.html file in your browser. Now, if you press the space bar, missles should fire from the front of the ship. Remember, to control the ship, you need to give Silverlight focus by clicking on the Silverlight control first (i.e just click on the ship).

Conclusion

And, another one bites the dust! This conversion took a bit longer because of the jump to objects, but it will come in handy for next time when we add multiple enemy ships. Stay tuned!

Share and Enjoy:
These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • StumbleUpon
  • Reddit
  • del.icio.us
Related Posts:
10 Minute Silverlight Game Programming Tutorial - Shootorial Conversion #4 (C#)
10 Minute Silverlight Game Programming Tutorial - Shootorial Conversion #2 (C#)
10 Minute Silverlight Game Programming Tutorial - Shootorial Conversion #5 (C#)
10 Minute Game Programming Tutorial: Silverlight - Shootorial #1 Conversion (C#)

Comments

One Response to “10 Minute Silverlight Game Programming Tutorial - Shootorial Conversion #3 (C#)”

  1. G.B. on February 1st, 2009 11:49 am

    This tutorial is awesome! Thanks so much.