Extension Methods and You
Extension methods are a new feature in C# 3.0 that we finally have full use of in our XNA games now that we are using Visual Studio 2008 (or Visual C# 2008 Express). Extension methods are simply static methods that are able to be used to simulate instance methods of any type. Put another way, extension methods let you implement new functionality in a static class, and execute it as if it was built in to the type, thus extending the type.
So where are these useful? Well, one of my new favorite places is with the GameTime type. Most people use the elapsed game time’s TotalSeconds property to get the elapsed time between frames so they can use a time based motion. This generally winds up with this everywhere:
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
Not really that bad, but it gets annoying having to cast and type that out each time. What we can do is make an extension method to expose this is a shorter, cleaner way:
public static class GameTimeExtensions
{
public static float GetElapsedSeconds(this GameTime gameTime)
{
return (float)gameTime.ElapsedGameTime.TotalSeconds;
}
}
Note the ‘this’ keyword in the method declaration. That indicates to the compiler that this is an extension method. Now when we want to use it, we can call it just like an instance method. So our line of code above now becomes:
float dt = gameTime.GetElapsedSeconds();
And that’s it. Another example is with 2D rendering. Generally speaking, I find that I like rounding all my Vector2 position values to integers for rendering to avoid strange filtering artifacts from trying to render to a partial pixel position. This usually looks like this:
spriteBatch.Draw(spriteTex, new Vector2((int)pos.X, (int)pos.Y), Color.White);
After a while, I got sick of all the casting and wrote up an extension method for it:
public static class Vector2Extensions
{
public static Vector2 ToIntVector(this Vector2 v)
{
return new Vector2((int)v.X, (int)v.Y);
}
}
So now to render I can use this simple method instead:
spriteBatch.Draw(spriteTex, pos.ToIntVector(), Color.White);
And my third example shows how you can use some more complex logic with your extension methods to hide some cool functionality into objects. For this I’m implementing a system for managing Viewports on a GraphicsDevice. So here’s the extension class:
public enum ViewportLocation
{
FullScreen,
TopHalf,
BottomHalf,
LeftHalf,
RightHalf,
TopLeftQuarter,
TopRightQuarter,
BottomLeftQuarter,
BottomRightQuarter
}
public static class GraphicsDeviceExtensions
{
public static void SetViewport(
this GraphicsDevice device,
ViewportLocation location)
{
Viewport viewport = new Viewport();
viewport.MinDepth = device.Viewport.MinDepth;
viewport.MaxDepth = device.Viewport.MaxDepth;
switch (location)
{
case ViewportLocation.FullScreen:
viewport.X = 0;
viewport.Y = 0;
viewport.Width = device.PresentationParameters.BackBufferWidth;
viewport.Height = device.PresentationParameters.BackBufferHeight;
break;
case ViewportLocation.TopHalf:
viewport.X = 0;
viewport.Y = 0;
viewport.Width = device.PresentationParameters.BackBufferWidth;
viewport.Height = device.PresentationParameters.BackBufferHeight / 2;
break;
case ViewportLocation.BottomHalf:
viewport.X = 0;
viewport.Y = device.PresentationParameters.BackBufferHeight / 2;
viewport.Width = device.PresentationParameters.BackBufferWidth;
viewport.Height = device.PresentationParameters.BackBufferHeight / 2;
break;
case ViewportLocation.LeftHalf:
viewport.X = 0;
viewport.Y = 0;
viewport.Width = device.PresentationParameters.BackBufferWidth / 2;
viewport.Height = device.PresentationParameters.BackBufferHeight;
break;
case ViewportLocation.RightHalf:
viewport.X = device.PresentationParameters.BackBufferWidth / 2;
viewport.Y = 0;
viewport.Width = device.PresentationParameters.BackBufferWidth / 2;
viewport.Height = device.PresentationParameters.BackBufferHeight;
break;
case ViewportLocation.TopLeftQuarter:
viewport.X = 0;
viewport.Y = 0;
viewport.Width = device.PresentationParameters.BackBufferWidth / 2;
viewport.Height = device.PresentationParameters.BackBufferHeight / 2;
break;
case ViewportLocation.TopRightQuarter:
viewport.X = device.PresentationParameters.BackBufferWidth / 2;
viewport.Y = 0;
viewport.Width = device.PresentationParameters.BackBufferWidth / 2;
viewport.Height = device.PresentationParameters.BackBufferHeight / 2;
break;
case ViewportLocation.BottomLeftQuarter:
viewport.X = 0;
viewport.Y = device.PresentationParameters.BackBufferHeight / 2;
viewport.Width = device.PresentationParameters.BackBufferWidth / 2;
viewport.Height = device.PresentationParameters.BackBufferHeight / 2;
break;
case ViewportLocation.BottomRightQuarter:
viewport.X = device.PresentationParameters.BackBufferWidth / 2;
viewport.Y = device.PresentationParameters.BackBufferHeight / 2;
viewport.Width = device.PresentationParameters.BackBufferWidth / 2;
viewport.Height = device.PresentationParameters.BackBufferHeight / 2;
break;
}
device.Viewport = viewport;
}
}
Now you can easily pick any half or quarter of the screen (or the whole thing) and just set that viewport with one method call:
graphics.GraphicsDevice.SetViewport(ViewportLocation.TopHalf);
Extension methods are a powerful way for you to add functionality based around existing types without the mess of standard static method syntax. Now that C# 3.0 is fully supported for XNA Game Studio 3.0, take advantage of them to help make your game code just a little bit cleaner.
Possibly Related Posts
(Automatically Generated)Spice up your PC input with extension methods
Finding Distances The Extension Way
Maintaining a fixed aspect ratio
Split screen in SunBurn
New Open Source Project Time

Fantastic stuff, just shows how much more there is to know with VS 2008.
Thanks for the samples, they will come in real handy.
Simon (Darkside) Jackson
http://thegamedevspace.spaces.live.com/