XNA Essentials

Game Programming for Xbox 360, PC + Windows Phone

NAVIGATION - SEARCH

Advanced Debugging Tutorial – Part Two

In the first tutorial we talked about some of the advanced debugging techniques. In this tutorial we will take it a step further and create a debugger visualizer. When we look at data while debugging, sometimes the default representation isn’t quite good enough. For example, the value of a Matrix variable is displayed as simply a string. We could make it into a table structure that actually represents the Matrix. We could also actually display the real color instead of just the color name or RGBA values.

In this tutorial we will be creating a color visualizer. When creating a debugger visualizer there are a few steps that have to take place. We need to do a few more things to get the visualizer be a Windows form that utilizes XNA.

image

Typically one would do the following steps to create a normal visualizer:

  1. Create a class library projects
  2. Add appropriate references (Microsoft.VisualStudio.DebuggerVisualizers; System.Windows.Forms)
  3. Create a class and make the class inherit from the abstract class DialogDebuggerVisualizer
  4. Override the Show method from the abstract class
  5. Add the assembly attribute DebuggerVisualizer setting the appropriate properties
  6. Copying the compiled assembly into one of two folders so Visual Studio can load it and use it

We will be altering the earlier steps a little since we are going to start off with a Creators Club Online Educational Example. We want our windows form to actually utilize XNA and there is no reason to reinvent the wheel. Let’s get started!

Start with the Educational Example: WinForms Series 1: Graphics Device

Extract this to a new folder called XNAVisualizer

Rename the project to XNAVisualizer

Rename the solution file to XNAVisualizer.sln

Open the solution file and rename the project in the Solution Explorer

Rename all of the namespaces to XNAVisualizer.

A shortcut for renaming all of the namespaces is to change one name and then click on the dropdown it makes and select “Rename ‘WinFormsGraphicsDevice’ to ‘XNAVisualizer’

image

Change the project type from Windows Form to Windows Library.

Double click on the Properties node in the Solutions Explorer. Under the Application tab change the Output Type from Windows Application to Class Library

image

While we have the properties window open, we can change the Assembly Name to XNAVisualizer

Delete the SpinningTriangleControl from the project.

Rename SpriteFontControl to ColorControl

We will be adding this control to the form later. This is the control that will display the color being debugged.

Add the following public field to the new ColorControl

public Color BackgroundColor = Color.CornflowerBlue;

Change the contents of the ColorControl’s Draw method to contain:

GraphicsDevice.Clear(BackgroundColor);

spriteBatch.Begin();
spriteBatch.DrawString(font, BackgroundColor.ToString(), new Vector2(10, 10), Color.Black);
spriteBatch.DrawString(font, BackgroundColor.ToString(), new Vector2(11, 11), Color.White);
spriteBatch.End();

In the Initalize method replace the following line:

content = new ContentManager(Services, "Content");

with these three statements:

Assembly visualizerAssembly = Assembly.GetExecutingAssembly();
content = new ContentManager(Services);
content.RootDirectory = visualizerAssembly.Location.Replace(
    visualizerAssembly.ManifestModule.Name, @"Content\"); 

Since this assembly will be running in a special folder we need to explicitly tell it where it can find the Content assets. We are using the Arial font from the original project. We are displaying the Color’s RGBA values using the font. The code is using reflection to get the executing assembly (our visualizer) and then setting the path to the path of the assembly and appends Content\ to the end of it. The Location property contains the full path including the assembly name (XNAVisualizer.dll). The ManifestModule.Name contains the assembly name as well. We are simply removing the assembly name from the path.

Since the code is using reflection we need to add the following using statement to the top of our ColorControl.cs file:

using System.Reflection;

 

Now we can bring our attention to the MainForm.

Remove all controls from the MainForm form

Double click on the MainForm.cs file

Click Ignore Errors and Continue

Remove the combo boxes, the split panel and delete each one. You may have to right click on the form and choose Select ‘spltContainer1’. Once it is selected you can hit the Delete button on the keyboard to remove it.

Make the form itself a lot smaller. For this we are simply wanting to display the color and the RGBA values of the color so it doesn’t need to be too large.

Compile the project and double click on the error to bring us into the MainForm.Designer.cs. Remove the SpinningTriangleControl and vspriteFontControl variables.

Remove the vertexColor_SelectedIndexChanged method from the MainForm class.

Remove the three vertexColors from the MainForm constructor.

Recompile to see 0 errors.

Open the design view of the MainForm again.

Re-add the ColorControl directly to the form by dragging it from the toolbar (under XNAVisualizer Components)

Expand the ColorControl so it fills up the entire form.

Change the form’s FormBorderStyle in the properties panel to FixedToolWindow. This keeps the window from being resized.

Change the Text of the window to “XNA Color Visualizer”

Drag the ColorDialog (from the toolbox under either the All Windows Forms or Dialogs tabs) to the form. This will create colorDialog1.

Double click on the ColorControl to create the _Click event.

Replace the contents of the MainForm class with the following:

public MainForm()
{
    InitializeComponent();
} 

public XnaColor Color
{
    get
    {
        return (colorControl1.BackgroundColor);
    }
    set
    {
        colorControl1.BackgroundColor = value;
        colorControl1.Invalidate();
    }
} 

private void colorControl1_Click(object sender, System.EventArgs e)
{
    if (colorDialog1.ShowDialog(this) == DialogResult.OK)
    {
        Color = new XnaColor(colorDialog1.Color.R, colorDialog1.Color.G, colorDialog1.Color.B, colorDialog1.Color.A);
    }
}

We added a public property Color. The example code declared XnaColor as a type to help distinguish from the XNA Color and the Windows Form Color. We are using the XnaColor type. We simply return the BackgroundColor of our colorControl when Get is called. And for Set we, we set the background color of the control as well as Invalidate our control so it will be redrawn. We could have hooked into the Idle event and called Invalidate continually, but there is no need for this control. The original example does this with the SpinningTriangleControl. Reading the WinFormsGraphicsDevice.htm file would be beneficial to see the pieces of the code we are using but not discussing like GraphicsDeviceControl, GraphicsDeviceService and ServiceContainer.

We populated the colorControl1_Click method by actually displaying the built in Windows Color Dialogbox. If the user clicks OK, we get the selected color from the dialog box and set our color property to the newly selected color. Our color property then sets the BackgroundColor property of the ColorControl. Note: This control does not let us change the Alpha value of the color.

 

The last thing we need to do is actually create our Visualizer code.

Add a new blank code file and name it ColorVisualizer.cs.  Paste the following code:

using System.Diagnostics;

using Microsoft.VisualStudio.DebuggerVisualizers;
using Microsoft.Xna.Framework.Graphics;

[assembly: DebuggerVisualizer(
    typeof(XNAVisualizer.ColorVisualizer),
    Target = typeof(Microsoft.Xna.Framework.Graphics.Color),
    Description = "XNA Color Visualizer")]

namespace XNAVisualizer
{
    public class ColorVisualizer : DialogDebuggerVisualizer
    {
        protected override void Show(IDialogVisualizerService windowService,
                                     IVisualizerObjectProvider objectProvider)
        {
            Color c = (Color)objectProvider.GetObject();

            using (MainForm form = new MainForm())
            {
                form.Color = c;

                windowService.ShowDialog(form);

                if (objectProvider.IsObjectReplaceable)
                {
                    if (form.Color != c)
                    {
                        objectProvider.ReplaceObject(form.Color);
                    }
                }
            }
        }

    }
}

We have to add a reference to the Microsoft.VisualStudio.DebuggerVisualizers assembly by clicking on the References tree node in the Solution Explorer under the XNAVisualizer project. Making sure we are on the .NET tab we scroll down and select the assembly and add it to our references.

The assembly attribute DebuggerVisualizer tells VisualStudio this is the entry point for the visualizer. It tells it what type of data it is visualizing as well as the description.

The visualizer class itself inherits from the DialogDebuggerVisualizer abstract class. We override the Show method to actually display our form with the data being investigated by the debugger. We look at the objectProvider object passed in and cast it to our Color type. We set the Color property on the MainForm to the value we are debugging. We then actually display the MainForm by calling ShowDialog on the windowService object passed in.

If all we wanted to do was display the color we would be done. However, it would be nice to actually change the color on the fly while debugging. This is why we added the Color Dialogbox. We first check to see if the object we are viewing is replaceable. It won’t be replaceable, for example, if we are debugging an enumerated type (i.e. Color.Black). However, if it is a variable holding a value then it will be replaceable and we replace the object by calling ReplaceObject on the objectProvider object passing in our new object (form.Color in this case). There is also a ReplaceData method, but we aren’t discussing that in this tutorial.

After compiling the assembly we need to place it in one of two directories:

\$Documents\Visual Studio 2008\Visualizers

or

\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers

Since we have Content assets we also want to copy the Content folder and any assets to the Visualizers folder as well. It can be tedious to copy the assemblies and content assets after every compile. We can create a Post Build Event command line to copy it for us. We need to open the properties of the XNAVisualizer project (by double clicking on the Properties node in the Solution Explorer) and go to the Build Events tab. Click on the Edit Post-build button and paste the appropriate variation of the following command and hit OK:

copy "$(TargetPath)" "C:\Users\<User Name>\Documents\Visual Studio 2008\Visualizers"
md "C:\Users\<User Name>\Documents\Visual Studio 2008\Visualizers\Content"
copy "$(TargetDir)\Content\*.*" "C:\Users\<User Name>\Documents\Visual Studio 2008\Visualizers\Content"

(Change the paths as needed)

Now when we run a regular XNA project and we want to debug the color we simply set the breakpoint and when we hover over the color variable we want to debug we click the Magnifying Glass icon which will bring up our newly created form.

Fortunately, the XNA Framework team did a lot of the heavy lifting for us (as usual) in this example by allowing us to utilize XNA in a Windows Form. We simply modified the example to be a Class Library and added the actual Visualizer code.

Debugging the Debugger Visualizer

To debug a debugger visualizer a static test method can be created and then a console app can be created to call the static method. This can be a great way to test the visualizer. Instead of creating a console app with all of the XNA assemblies referenced, I debugged the visualizer by  attaching to another Visual Studio instance.

In the Debugger Visualizer project click on Debug / Attach to Process. A dialog will come up. Select Visual Studio instance you want to debug. This would be your real XNA project that has a XNA Color variable.

image

Now when we set a break point in the main XNA project and hover over a Color variable and hit the magnifying glass it will kick off the Visualizer Debugger and if we had a breakpoint we could step though the code. Pretty cool!

 

A great next step would be to create another visualizer in this project to display Matrices.

For more reading on Visualizers look in the following here.

Download the code from this tutorial here.

Happy Coding!

-Chad

Advanced Debugging Tutorial - Part One

In order to make games or any application these days it really helps to understand how the debugger works in your IDE. Since this site is all about XNA and specifically XNA Game Studio and the XNA Framework our IDE of choice is Visual Studio / Visual C# Express. For this series the majority of the tips are only available in Visual Studio (denoted by *). This series is going to discuss some cool tips and tricks for debugging our applications. Let's get started ...

Simple Breakpoints

Setting a break point is pretty simple by either clicking in the "Gutter" on the IDE or hitting F9. Doing this will toggle the breakpoint to be present or not.

image

Also we can display debugging information in the output window inside of the IDE. For example, if we use the following code:

System.Diagnostics.Debug.WriteLine("This is my debug message.");

We can see the results printed in the Output window of the IDE:

image

If we want to leave a breakpoint location, but want to disable it we can right click on the breakpoint and choose Disable Breakpoint. (Take note of the other options as we will be discussing them a little later)

image

After the breakpoint is disabled it is represented by a circle:

image

This can be beneficial as well, but we can do better than basic breakpoints and glorified printf statements.

Advanced Breakpoints*

Now we can get to the meat of the tutorial! The first thing to note is that it is best to start the debugging before setting up advanced breakpoints. It is not required, but the benefit is that the symbol tables are available instead of only Intellisense.

The Advanced Breakpoint image  allows setting a hit count, a condition or a filter.

Hit Count

To set a hit count, simply right click on a basic breakpoint and select "Hit Count" from the context menu. The following dialog will be displayed:

image

The code will execute skipping over the breakpoint until that line is called 1,000 times.

Here are the options available from the Breakpoint Hit Count dialog box:

 image

The first option, "break always", describes a basic breakpoint where anytime that code is about to be executed we break into the code.

The second and last options are easy enough to comprehend as the code will only break when the code has been executed a certain number of times.

The third option, "break when the hit count is a multiple of", can be thought of as a modulus calculation. If we used the value 60 for example, then we are asking the compiler to break execution every 60th time the code is executed. For XNA Games this could break the code once a second assuming we were running at 60fps and the break point was in the appropriate method.

Condition

Not only can we specify a hit count for our advanced breakpoint, but we can also specify a condition.

image

Just as the description reads, this will evaluate the expression entered and will only break if the expression is true or if the expression has changed. An interesting thing to note here is that it actually executes code. For example, if we were in a for loop with a typical index variable of i we could actually cause an infinite loop if we were not careful. In C# we do comparisons by using a double equal sign (==). A single equal sign (=) is used for setting values. So if we wanted to break when our for loop indexer i hit 20 but we put i=20 in the box then every time the compiler executed the expression it would actually set our variable i to 20 effectively causing our for loop to last forever (assuming the condition to break out of the for loop is when i is greater than some value over 20). So be careful to actually use a comparison operator.

An expression can be as simple as a variable. We could simply put in "i" (without quotes) and set the "Has changed" radio button. This would break the execution whenever the variable "i" had a value change.

Methods could even be called from this window. An entire debug class could be created that checks values for nulls or whatever is required. So something like DebuggerHelper.CheckValue(someValue) would be valid assuming that CheckValue returns a boolean type.

Filter

We can also set break points on certain machines, processes and/or threads.

image

For this dialog, even in C# using a single equal sign is allowed. Fortunately, the typical double equal signs is also allowed. Assuming our application had multiple threads (which can be helpful for long running content loads, etc) we can break the code only when we are in a particular thread. In this example it is assumed we have a thread created and we explicitly named it "SomeWorkerThread". When any other thread executes the code we have set this breakpoint on, the code will not break. However, as soon as the thread we specified hits the code the execution will be paused.

Stepping through threaded code can be aggravating since stepping through the code will jump all over the place if we do not know how to ignore other threads. Fortunately we can do this by making sure our debug toolbar is visible by selecting it from the View > Toolbars > Debug menu item:

image

This will bring up the following toolbar:

image

To view the other threads while debugging our code we can select the "Show Threads in Source" button image

Using this toolbar we can also open the Breakpoints window by clicking the "Breakpoints" button image

This brings up the following window where we can more easily manage our breakpoints:

image

By clicking on the Columns button we can add the columns we want. By default Hit Count, Filter and When Hit are not displayed.

OK, back to our threading issue...

First it would be nice to see all of the threads in the app. Well just like our Breakpoints window we can bring up the Threads window by clicking Debug > Windows > Threads or pressing CTRL + D, T

 image

We can see which piece of code our threads are in here. Remember by clicking the image button we can see the current location of the running thread by looking at the "Gutter" in the IDE (the same area where the breakpoint icons are displayed).

image

The last thing to note about Advanced Breakpoints is that Hit Counts, Conditions and Filters are ANDed together. So all conditions need to be met to actually break into the code.

Debugging .NET Framework Source Code*

Sometimes it can be beneficial to actually break into the .NET Framework source code when debugging. Yes, there is Reflector, but you can't exactly step into the code and you can't see the comments. Stepping into the .NET Framework code can be beneficial when some operation is failing (like the system saying a file doesn't exist when it definitely appears it does). By stepping through the code it may actually show that it is really an access denied error.

In order to enable the .NET Framework source stepping simply by going to Tools > Options and checking the "Enable .NET Framework source stepping" check box under Debugging / General as shown below:

image

After getting the dialog box that "Just My Code" is no longer selected you will see another dialog box talking about symbols. To get to the location simply click the Symbols tree node under Debugging.

image

You then need to add the following symbol locations:

http://referencesource.microsoft.com/symbols

http://msdl.microsoft.com/download/symbols

Then in the "Cache symbols from symbol servers to this directory" enter a permanent folder such as:

c:\dotnetsymbols

The next time you debug you will get a dialog box with a EULA for the source code.  Instead of only downloading pieces of the framework as you are working on it you may want to download all of it at once. This can especially be helpful if you work offline. There is a codeplex project, NetMassDownloader, that does just that.

Evaluation Windows

While discussing breakpoints we touched on the evaluation of breakpoint conditions. This evaluation functionality is also available in a few other windows as well.

Locals, Auto and Watch Windows

You can add particular variables to the Watch window. The Locals and Auto windows are populated / depopulated based on the scope of the application. You can click in the Value column and modify the value. This doesn't only work for value types but it also works for reference types. For example the texture greyAsteroid has a value assigned to it, but I am redefining it at runtime by typing in Content.Load<Texture2D>(@"Textures\asteroid1") in the Value column and pressing enter.

image

It is also legal to just create a new object. For example entering new SomeClass() would be a valid entry for the appropriate variable.

There is a little know feature called Make Object ID*. Simply right click on the row with a reference type and select Make Object ID.

 image

It will then associate an object id, for example {1#}, to the object. Since both my greyAsteroid and originalAsteroid variables are both member fields I knew they wouldn't go out of scope so I created a temporary test variable. When I create an Object ID for this variable I now have the following:

 image

Now the benefit of creating an Object ID is that I can see the memory even after it goes out of scope. I just need to type 1# as a new Watch item. Doing this and then stepping out of the method gives me the following results:

image

Notice the test object is out of scope and it is grayed out. Yet, I still have access to the object id. I can continue to look at the memory until the garbage collector runs. I'm not guaranteed how much longer it will be around, but this can be handy in advanced scenarios.

We can even check to see what generation the of the garbage collector the variable is in. We can add GC.GetGeneration(1#) in the Watch window and see the following result:

image

That is pretty cool!

Immediate Window

For the command link junkies there is the Immediate window. This is actually my favorite window. Just like the others you can evaluate expressions. You can also create new objects that you can evaluate at runtime. For example, you can type in

? SomeClass x = new SomeClass();

And then in the Watch window you can watch the value by entering $x.  Now not only can we set simple value types like bool, int, float, etc but we can create a new reference type and then set a value in our code to that new reference while debugging. This can also come in handy.

By the way, ? comes from the Visual Basic days and is short hand for print.

Summary

We discussed basic breakpoints, advanced breakpoints with filters, hit counts and conditions. Hopefully there was information in here that you didn't know existed. This can really help speed up development.

Well that is enough information to think on for this blog post. In the next installment I will walk through creating a Visualizer for Visual Studio.

* Not available in Visual C# Express

Happy Debugging!

Chad