Silverlight Games 101

Write games in Silverlight 2 using C# by Bill Reiss
Our upcoming Silverlight book for beginners (includes a great chapter on game development in Silverlight!) Hello! Silverlight 2 with Dave Campbell, available online now!



Pages

    Recent posts

    Navigation

    Archive

    Blogroll

      Tampa Divorce Lawyer

      North of Tampa in Lutz, Florida. A Tampa Divorce Lawyer focusing on family, divorce, and real estate law.

      Disclaimer

      The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

      The Start of a Game Helper Class Library

      Updated June 9, 2008 for Silverlight 2 Beta 2

      Note: This tutorial has been updated to fix a bug in the DispatcherTimerGameLoop class, where the timer would start upon creation instead of waiting for the Start() method.

      Source code: http://silverlightrocks.com/cs/files/folders/silverlight_2_tutorials_source_code/entry337.aspx

      So I did this with the old tutorials, and a little differently, this time I'm going to try to keep it a bit cleaner and to follow better namespacing and project layout, etc. One of the goals of this blog is to help you write games faster, and one way to do that is to give you some helper classes that can get you going and you can use in your own games. I have added a class library project to the SpaceRocks solution called BlueRoseGames.Helpers and when it makes sense, I'll add classes there so that you can use them in your own projects.

      Anything that I add to that class library or anything else I blog about here you are welcome to use and modify in your own games and redistribute freely. It is all provided "as is", and if you're using it for any other purpose than in your own applications (for example, if you wanted to redistribute it as part of your own library, etc) please contact me for permission.

      Ok so now that that's out of the way, the first thing I've added to the Helpers class library is the two game loop implementations (Storyboard and DispatcherTimer) that were covered in the Creating a Game Loop tutorials. They both inherit from an abstract GameLoop class and can be used easily in your own game. First the code...

      GameLoop.cs:

      using System;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Documents;
      using System.Windows.Ink;
      using System.Windows.Input;
      using System.Windows.Media;
      using System.Windows.Media.Animation;
      using System.Windows.Shapes;
       
      namespace BlueRoseGames.Helpers.Timers
      {
          public struct GameLoopUpdateEventArgs
          {
              public GameLoopUpdateEventArgs(TimeSpan elapsed)
              {
                  Elapsed = elapsed;
              }
       
              public TimeSpan Elapsed;
          }
       
          public abstract class GameLoop
          {
              protected DateTime lastTick;
              public delegate void UpdateHandler(object sender, GameLoopUpdateEventArgs e);
              public event UpdateHandler Update;
       
              public void Tick()
              {
                  DateTime now = DateTime.Now;
                  TimeSpan elapsed = now - lastTick;
                  lastTick = now;
                  if (Update != null) Update(this, new GameLoopUpdateEventArgs(elapsed));
              }
       
              public virtual void Start()
              {
                  lastTick = DateTime.Now;
              }
       
              public virtual void Stop()
              {
              }
          }
      }

      So what we have are a Start, Stop, and Tick method, and an Update event that provides the elapsed time since the last update. By providing this abstract class, it is easy to swap out the two timers for each other without changing other code.

      Now for the Storyboard technique. This class is called StoryboardGameLoop.

      StoryboardGameLoop.cs:

      using System;
      using System.Windows;
      using System.Windows.Media.Animation;
       
      namespace BlueRoseGames.Helpers.Timers
      {
          public class StoryboardGameLoop : GameLoop
          {
              bool stopped = true;
              Storyboard gameLoop = new Storyboard();
       
              public StoryboardGameLoop(FrameworkElement parent) : this(parent, 0)
              {
                  
              }
       
              public StoryboardGameLoop(FrameworkElement parent, double milliseconds)
              {
                  gameLoop.Duration = TimeSpan.FromMilliseconds(milliseconds);
                  gameLoop.SetValue(FrameworkElement.NameProperty, "gameloop");
                  parent.Resources.Add("gameloop", gameLoop);
                  gameLoop.Completed += new EventHandler(gameLoop_Completed);
              }
       
              public override void Start()
              {
                  stopped = false;
                  gameLoop.Begin();
                  base.Start();
              }
       
              public override void Stop()
              {
                  stopped = true;
                  base.Stop();
              }
       
              void gameLoop_Completed(object sender, EventArgs e)
              {
                  if (stopped) return;
                  base.Tick();
                  (sender as Storyboard).Begin();
              }
          }
      }

      The constructor takes a FrameworkElement, since Storyboards need to be added to the Resources collection of a FrameworkElement, and optionally a milliseconds between updates value. This will default to 0 if not specified.

      The DispatcherTimerGameLoop is similar.

      DispatcherTimerGameLoop.cs:

      using System;
      using System.Windows.Threading;
       
      namespace BlueRoseGames.Helpers.Timers
      {
          public class DispatcherTimerGameLoop : GameLoop
          {
              DispatcherTimer t = new DispatcherTimer();
              public DispatcherTimerGameLoop() : this(0)
              {
              }
       
              public DispatcherTimerGameLoop(double milliseconds)
              {
                  t.Interval = TimeSpan.FromMilliseconds(milliseconds);
                  t.Tick += new EventHandler(t_Tick);
              }
       
              public override void Start()
              {
                  t.Start();
                  base.Start();
              }
       
              public override void Stop()
              {
                  t.Stop();
                  base.Stop();
              }
       
              void t_Tick(object sender, EventArgs e)
              {
                  base.Tick();
              }
       
          }
      }

      Now to use these in our game. The Page class gets a lot simpler. First the constructor:

      public Page()
      {
          InitializeComponent();
      //     StoryboardGameLoop gameLoop = new StoryboardGameLoop(this);
          DispatcherTimerGameLoop gameLoop = new DispatcherTimerGameLoop();
          gameLoop.Update += new GameLoop.UpdateHandler(gameLoop_Update);
          gameLoop.Start();
      }

      Pretty straightforward stuff. We create our game loop object, wire up its Update event, and start the game loop. If you want to use a DispatcherTimer instead, comment out the game loop declaration and uncomment the other one.

      Then all that's left is to handle the Update event:

      void gameLoop_Update(object sender, GameLoopUpdateEventArgs e)
      {
          // do your game loop processing here
          ship.RotationAngle += 100 * e.Elapsed.TotalSeconds;
      }

      I went through this pretty quickly because the details about how the game loop works have already been covered, and this was basically a refactoring. I hope you get good use out of these helper classes and others that I'll add along the way.

      Share this post : digg it! dotnetkicks it! technorati!
      Posted: Mar 27 2008, 21:26 by Bill Reiss | Comments (21) RSS comment feed |
      • Currently 0/5 Stars.
      • 1
      • 2
      • 3
      • 4
      • 5
      Filed under:

      Comments

      Comments are closed