XNA Framework GameEngine Development. (Part 2, FpsCounter:GameComponent)
Introduction
Welcome to Part 2 of the XNA Framework GameEngine Development series. In this article, I will introduce the GameComponent architecture by creating a FramesPerSecond counter (FPS). The XNA Framework has a very nice feature that allows us to encapsulate GameComponents. This has two nice side effects:
-
Functionality is naturally encapsualted
-
GameComponents become plug and play reuseable.
So this engine will take advantage of this prebuilt architecture as much as possible.
How fast am I rendering?
An FPS counter is probably the simplest GameComponent we will be creating and is that makes it the best place to start. Shawn Hargreaves has a very nice explantion of what we are about to do, so if you want a more in depth discussion, take the time to visit his blog.
I am going to make a slight change to what he has cause I dont want SpriteBatches and DrawableGameComponents all over the place. I would prefer to have a little finer control over Gamecontent and where things are rendered.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace RoeEngine2.GameComponents
{
public class FpsCounter : GameComponent
{
private float updateInterval = 1.0f;
private float timeSinceLastUpdate = 0.0f;
private float framecount = 0;
private float fps = 0;
/// <summary>
/// The frames per second.
/// </summary>
public float FPS
{
get { return fps; }
}
public FpsCounter(Game game)
: base(game)
{
Enabled = true;
}
/// <summary>
/// Update the fps.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
float elapsed = (float)gameTime.ElapsedRealTime.TotalSeconds;
framecount++;
timeSinceLastUpdate += elapsed;
if (timeSinceLastUpdate > updateInterval)
{
fps = framecount / timeSinceLastUpdate; //mean fps over updateIntrval
framecount = 0;
timeSinceLastUpdate -= updateInterval;
if (Updated != null)
Updated(this, new EventArgs());
}
}
/// <summary>
/// FpsCounter Updated Event.
/// </summary>
public event EventHandler<EventArgs> Updated;
}
}
Good, nothing fancy here. That is how we want it, easy to understand code when we come back in a month or a year to squash silly bugs.
Adding GameComponents to the Engine.
Now that we have created our first Gamecomponent, we should add it to the BaseEngine. Add the following property to the RoeEngine2 class.
private static FpsCounter _fpsCounter = null;
/// <summary>
/// The frames per second counter.
/// </summary>
public static FpsCounter FpsCounter
{
get { return _fpsCounter; }
}
Now add the following code to the RoeEngine2 constructor.
/// <summary>
/// Create RoeEngine
/// </summary>
/// <param name="windowsTitle">Window Title</param>
protected RoeEngine2(string windowsTitle)
{
//...Graphics Manager Stuff...
// Init the FpsCounter
_fpsCounter = new FpsCounter(this);
Components.Add(_fpsCounter);
//TODO include other inits here!
}
Remember we do not want to actually instantiate the RoeEngine anywhere accept the EngineManager. So to test out that our FpsCounter works, we should add the following to the EngineManager.Draw() method.
protected override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
Device.Clear(BackgroundColor);
// This is the new, but temporary line of code.
this.Window.Title = FpsCounter.FPS.ToString();
}
Conclusion
We now have a good model for adding new features to our engine. We have a reusable design that is naturally encapsulated. I know this was easy, things are going to pick up soon.
Please feel free to leave comments or suggestions, your feedback is very important to the health and longevity of this blog.
suggestion: implement a DrawableGameComponent to draw FPS on the screen, instead of using title…
Thank you for your comments and interest in this blog. I understand your suggestion for using Drawable Game Component and drawing a SpriteBatch from this object. However, my plan for managing game content is to use a ScreenManager to help control some of these SpriteBatches. Since I am using YagNi design principles, I decided to just do what I would need at this point in the series.
[...] I: Basic engine skeleton Part II: An FPS counter GameComponent Part III: Applying TDD (Test Driven Development) Part IV: ShaderManager GameComponent Part V: [...]
Pingback by Getting up with XNA GS 2.0 [UPDATED] - Kartones Blog | February 19, 2008 |
I would like to ask whether in this section is not used in the following code, it can be done then?
if (Updated != null)
Updated(this, new EventArgs());
public event EventHandler Updated;
I found a small mistake (well, more like something you forgot to say).
Remember to add:
using RoEngine2.GameComponents;
at the beginning of your RoEngine2 class. At least, for me it didn’t work without it. Or did I do something wrong?
It didn’t recognize the FPSCounter class.
Cheers!
PS: This is awesome
Thanks.
Thank you Morgawr, true it is very important to have the using statement. Otherwise the code will simply not compile. Thank you for pointing this out.