Recommended

  • Silverlight 4 Podcast Pack with Tim Heuer
  • Building Modular Silverlight Applications
  • Prism -  10 Things to Know
  • Securing Silverlight Application and WCF Service using ASP.Net Authentication Techniques
  • Model– View – ViewModel in Silverlight
Skip Navigation LinksHome / Articles / View Article

Creating a Game Loop Part 2

+ Add to SilverlightShow Favorites
0 comments   /   aggregated from Silverlight Games 101 on Mar 15, 2008  /  original article
(0 votes)
Categories: Games , Samples

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

Ok so I got a few comments after the last post asking why I didn't use the new DispatcherTimer for my game loop. The answer is that that is what this post was going to be about, and it still is.

I've done a bit more experimenting with the two different techniques (Storyboard or DispatcherTimer) and have come up with the following observations. I encourage you to do your own tests and see if you get the same results.

The Storyboard timer seems to provide smoother animations, and I think this makes sense, since the repositioning of the sprites is in sync with the frame rate. The DispatcherTimer has no idea when the frames are being rendered, it's running in a different thread. So why use a DispatcherTimer? Well from some limited testing, it seems that it is more efficient on the CPU, it's simpler to implement, and doesn't need to be bound to a FrameworkElement. Also, the DispatcherTimer technique is better supported in WPF, so if you are writing code that you want to use on both, you may want to use a DispatcherTimer.

So let's see how the game loop looks with a DispatcherTimer.

Technique #2: Using a DispatcherTimer for the game loop

First let's make it easier for both types of timers to call the game loop logic. We can do that by creating an Update method in the Page class which we will put our update logic in. The updated gameLoop_Completed and Update methods are as follows:

   1: void gameLoop_Completed(object sender, EventArgs e)
   2: {
   3:     Update();
   4:     gameLoop.Begin();
   5: }
   6:  
   7: void Update()
   8: {
   9:     // do your game loop processing here
  10:     ship.RotationAngle++;
  11: }

Now if you run the program, it should still act just as it did before. The DispatcherTimer class is in the System.Windows.Threading namespace, so let's add a using statement for that to the Page.xaml.cs file:

   1: using System.Windows.Threading;

And then in the Page_Loaded method, let's make it so that we can use either technique by changing a preprocessor directive. So we'll wrap the Storyboard code in a #if statement, and then put the DispatcherTimer code in a #else statement:

   1: void Page_Loaded(object sender, RoutedEventArgs e)
   2: {
   3: #if USE_STORYBOARD_TIMER
   4:     gameLoop = new Storyboard();
   5:     gameLoop.SetValue(FrameworkElement.NameProperty, "gameloop");
   6:     this.Resources.Add(gameLoop);
   7:     gameLoop.Completed += new EventHandler(gameLoop_Completed);
   8:     gameLoop.Begin();
   9: #else
  10:     DispatcherTimer t = new DispatcherTimer();
  11:     t.Interval = TimeSpan.FromMilliseconds(1000 / 60.0);
  12:     t.Tick += new EventHandler(t_Tick);
  13:     t.Start();
  14: #endif
  15: }

The Interval of the timer is 1000/60 milliseconds, or the time between frames if the frame rate is 60. You can change this value to be consistent with your frame rate.

Now we need a t_Tick method to handle the Tick event, we'll simply call the Update method in there:

   1: void t_Tick(object sender, EventArgs e)
   2: {
   3:     Update();
   4: }
   5:  

And now if you run the program, it should behave roughly the same as when we had a Storyboard timer. One difference is that at least when I run it, it rotates slower using this technique. It seems that the DispatcherTimer doesn't actually fire every 16.66667 milliseconds like it's supposed to, and I don't know if that is something they are going to improve, but this brings up a game programming technique that you should familiarize yourself with.

Typically you should not rely on timers firing exactly when you expect them to unless you're using a timer that guarantees it will fire on a certain interval, since things can happen, like the machine is bogged down with other work, etc. If you go back now and play some of the early PC games on modern hardware, they will be unplayable because they are running so fast. This is because their timers were based on the CPU speed, and as processors got faster, there was nothing in their game to account for this.

So how can we take care of this? If we keep track of the time since the last Update call, and then use this time difference in our calculations, then it won't matter if the timer fires once a second, the animation will be very choppy, but it will still run at the same speed.  First let's declare a DateTime field in the Page class to store the last update time:

   1: DateTime lastUpdate;

and then in the Page_Loaded method we'll initialize it the first time:

   1: lastUpdate = DateTime.Now;

and then in the Update method, we need to find the TimeSpan since the last update, set the new lastUpdate time, and then use the time since last update in our calculations:

   1: void Update()
   2: {
   3:     DateTime now = DateTime.Now;
   4:     TimeSpan elapsed = now - lastUpdate;
   5:     lastUpdate = now;
   6:     // do your game loop processing here
   7:     ship.RotationAngle += 100 * elapsed.TotalSeconds;
   8: }

Now no matter how long between Updates, the ship will rotate at the same speed. Next time we'll look at how we can encapsulate this game loop logic to make it easier to use in other projects.

Share this post : digg it! dotnetkicks it! technorati!
Share


Comments

Comments RSS RSS
No comments

Add Comment

 
 

   
  
  
   
Please add 7 and 8 and type the answer here: