Running on Empty

The few things I know, I like to share.

XNA Framework GameEngine Development. (Part 3, TDD)

Introduction

Welcome to Part 3 of the XNA Framework GameEngine Development series.  In this article, I will introduce the Test Driven Development piece of the game engine.  Better late than never.

There are plenty of articles covering TDD so I will not argue the benefits here.  I personally see TDD as just another tool for writing good code, starting early and writing test cases often is always “The Best Practice”.  The simple fact that I am introducing TDD in the 3rd article of the series indicates I am not an extremist.  I would be happy to entertain your thoughts and suggestions.

Creating a Unit Test Project (Updated to use Managers Namespace)

I chose to use NUnit as my unit tester, mainly because it is free and is what I use at work.  Also, please note, I do not use the Express Additions of Visual Studio, I have no experience setting up TDD in VS Express.  If you have questions or experiences please feel free to leave a comment.  Updated, KaBaL was kind enough to provide some code for the Visual Studio Team Suite test cases, please see below.

First, create a new windows class library project, I named mine RoeEngine2UnitTests.  You will need to reference your game engine project as well as, Microsoft.Xna.Framework, Microsoft.Xna.Framework.Game, and the nuit.framework.  Most likely you will also have a couple System references at this point, keep those as well.

Next, Rename or Delete/Add the Class1.cs file to RoeEngineTestCases.cs and add the following code.

 Note:  Updated, thanks to KaBaL for pointing out that I renamed the namespace Manager to Managers.

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using RoeEngine2.Managers;
using Microsoft.Xna.Framework;

namespace RoeEngine2UnitTests
{
    [TestFixture]
    public class RoeEngineTestCases
    {
        private EngineManager _game = null;
        private const string _windowTitle = "UNITTEST";

        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
            _game = new EngineManager(_windowTitle);
            EngineManager.Game = _game;
            _game.Activated += new EventHandler(game_Activated);
            _game.Run();
        }

        void game_Activated(object sender, EventArgs e)
        {
            _game.Exit();
        }

        [TestFixtureTearDown]
        public void TeardownTestFixture()
        {
            _game = null;
        }

        [Test]
        public void GameStartup()
        {
            Assert.IsNotNull(_game);
            Assert.IsNotNull(EngineManager.Game);
            Assert.IsNotNull(EngineManager.Device);
            Assert.IsNotNull(EngineManager.ContentManager);
            Assert.AreEqual(_windowTitle, EngineManager.WindowTitle.ToString());           
        }

        [Test]
        public void FpsCounterCreated()
        {
            Assert.IsNotNull(EngineManager.FpsCounter);
            Assert.AreEqual("0", EngineManager.FpsCounter.FPS.ToString());
        }
    }
}

Finally, we are ready to run our test cases.  Open up NUnit and navigate to your bin/Roeengine2UnitTests.dll file.  Run the project and voila! Updated… This is what makes the open source community so great.  The following was contributed by KaBaL.

using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RoeEngine2.Managers;
using Microsoft.Xna.Framework;

namespace RoeEngine2UnitTest
{
    ///
    /// Summary description for UnitTest1
    ///
    [TestClass]
    public class UnitTest1
    {
        private EngineManager _game = null;
        private const string _windowTitle = "UNITTEST";

        [TestInitialize()]
        public void TestInitialize()
        {
            _game = new EngineManager(_windowTitle);
            EngineManager.Game = _game;
            _game.Activated += new EventHandler(game_Activated);
            _game.Run();
        }

        void game_Activated(object sender, EventArgs e)
        {
            _game.Exit();
        }

        [TestCleanup()]
        public void TestCleanup()
        {
            _game = null;
        }

        [TestMethod]
        public void GameStartup()
        {
            Assert.IsNotNull(_game);
            Assert.IsNotNull(EngineManager.Game);
            Assert.IsNotNull(EngineManager.Device);
            Assert.IsNotNull(EngineManager.ContentManager);
            //Assert.AreEqual(_windowTitle, EngineManager.WindowTitle.ToString());
        }

        [TestMethod]
        public void FpsCounterCreated()
        {
            Assert.IsNotNull(EngineManager.FpsCounter);
            Assert.AreEqual("0", EngineManager.FpsCounter.FPS.ToString());
        }

        public UnitTest1()
        {
            //
            // TODO: Add constructor logic here
            //
        }
    }
}

 


Conclusion

We have just set up a very basic testing environment for our engine.  Remember, all of this is optional, TDD may not be for everyone.  I strongly urge you to use it, but you know your skillsets better than I.

Please feel free to leave me any comments or suggestions/improvements to the code you see here.

January 10, 2008 Posted by | C#, TDD, XBOX360, XNA | 19 Comments

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.

January 10, 2008 Posted by | C#, GameComponent, XBOX360, XNA | 9 Comments

WPF UserControls as a Modal-like Dialog.

Introduction

This article is in direct response to feedback from the WPF Popup Controls series.  What if you needed a User Control to “popup” as a Windows Dialog, have all the properties of a Windows Dialog, but behave as a Popup Control.

Creating a UserControl…plus a little something extra.

Create a WPF User Control as you would normally, but you will want to make certain you put at least one button on the UserControl.

<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="120" Height="50"/>

Now include a RoutedEvent using the Bubble RoutingStrategy for the button you just created.  This will allow any Page or Window that implements this control to intercept the ClickEvent.Place a couple of Methods that will Show and Hide the user control.  You could also create Dependency Properties at this point to pass Properties between the Parent and the UserControl, not shown here though.

namespace TestCase.UserControls
{
    public partial class TestControl : UserControl
    {
        #region Events

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(CancelButtonClickEvent));
        }

        #endregion

        #region RoutedEvents

        public static readonly RoutedEvent CancelButtonClickEvent = EventManager.RegisterRoutedEvent(
            "CancelButtonClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TestControl));
        public event RoutedEventHandler CancelButtonClick
        {
            add { AddHandler(CancelButtonClickEvent, value); }
            remove { RemoveHandler(CancelButtonClickEvent, value); }
        }
      
        #endregion

        public TestControl()
        {
            InitializeComponent();
        }

        public void Show()
        {
            Visibility = Visibility.Visible;
        }

        public void Hide()
        {
            Visibility = Visibility.Collapsed;
        }
    }
}

Using the UserControl.

You will now need to declare the user control on a Window or Page.  This means the Page or Window Header needs to declare the namespace for your UserControl.

xmlns:UserControls="clr-namespace:TestCase.UserControls"

Now finally we are ready to declare our user control.

<UserControls:TestControl HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"
                          Width="Auto" Height="Auto" Visibility="Collapsed"
                          x:Name="TestUserControl"
                          CancelButtonClick="TestUserControl_CancelButtonClick" />

Notice the control Visiblilty property is set to Collapsed.  We now need to write the code behind, our main focus will be to display and hide the user control.

private void TestUserControl_CancelButtonClick(object sender, RoutedEventArgs e)
{
    HideTestUserControl();
}

private void ShowTestUserControl()
{
    TestUserControl.Show();
}

private void HideTestUserControl()
{
    TestUserControl.Hide();
}

On the main parent Page or Window, simply wire up a Button click or some other user Event and call ShowTestUserControl().

Making it look Pretty.

You will most likely want to make the background control grey out to indicate focus is now on your User Control as well as steal focus from the Parent Window while the user control is active.  This can easily be accomplished using a rectangle.

Add the following code to your AppStyles.xaml

  <Style x:Key="UserControlOverlayRectangleStyle" TargetType="{x:Type Rectangle}">
    <Setter Property="Fill" Value="#FF151515"/>
    <Setter Property="Opacity" Value="0.61"/>
  </Style>

Also add the following code to your UserControl.

<Grid Opacity="1" Width="Auto" Height="Auto" Background="{x:Null}">
     <Rectangle Name="MainRectangle" Margin="0,0,0,0" Style="{DynamicResource UserControlOverlayRectangleStyle}"/>
     <!-- Everything Else -->
</Grid>

Conclusion

We now have a simple way to add declare user controls on a Page or Window and have them behave as Dialog Windows. 

Please feel free to leave suggestions or comments.  I look forward to your feedback.

January 10, 2008 Posted by | C#, WPF, XAML | 12 Comments