Introduction to C++ with Game Development: Part 7, Debugging

00000000000000000000000000000000
0
Anonymous Dec 05, 2011 at 07:48 c game-programming

In this tutorial, we're going to look at how you can stop and start your code to see what it is doing as well as view some variables and values. This is a process called debugging, it can be a complex process but we'll stick with the basics of breakpoints, and following program flow while keeping an eye on variables.

Getting the stuff you need

As with the last tutorial, we'll use the template again. Extract the package to a fresh directory (say, c:\my_projects\debug) and load up the .sln file. Remove the 'hello world' stuff in the Tick function.

Debug Mode

First of all, we must make sure that when you are running your program you are in debug mode. When you first load up your project, this is already the case, but let's be sure:

Debug Mode

Look at the options you have on the drop down window on your toolbar and make sure Debug Mode is selected.

Sprites Again

Yes.. more sprites, but its best that we have something on screen that we know works.

So as before lets put a sprite on screen. Add a Sprite variable above the Tick function like this:

Sprite theSprite( new Surface("assets/ctankbase.tga"), 16 );

void Game::Tick( float a_DT )
{
...

Now make once again your Tick function like this:

void Game::Tick( float a_DT )
{
	m_Screen->Clear( 0 );
	theSprite.Draw( 0, 0, m_Screen );
}

Run the program and make sure you can see your tank. Again lets make it move. Add a tankY variable.

int tankY=0;

void Game::Tick( float a_DT )
{
...

and change the Tick function to make it look like this:

void Game::Tick( float a_DT )
{
	m_Screen->Clear( 0 );
	theSprite.Draw( 0, tankY, m_Screen );
	tankY = tankY + 1;
	if( tankY > 430 )
	{
		tankY = 1;
	}
}

You should be an old pro at this by now. Run your program and you will see your tank moving top to bottom and resetting; quite fast, because we are using ints. Now, lets add something. Carefully add the following after this

	if( tankY > 430 )
	{
		tankY = 1;
	}

	if (tankY = 200)
	m_Screen->Print( "My Tank is at 200", 2, 2, 0xffffff );

Now hopefully you will have already spotted a very simple typing error. Depending on your compiler settings it may even have warned you of the error. Please take a moment to look at the code before going to the next page. Can you see the problem?

We've used = instead of == in our condition test.

Remember that = is an assignment, it causes tankY to become 200 rather than test if tankY is equal to 200. This is a very common type of typo error and you will soon learn to spot and avoid these kinds of typing errors which can legally compile.

Now you already know the fault, but lets pretend that you do not, and lets try using our debugger to locate the problem. Run the code. You will see the tank sticks in the middle of the screen and the printout stays on screen all the time. Now clearly this is not what we want it to do: our plan is to have the tank move and then when it gets to screen Y 200, it should print up some text.

Now is the time to use our debugger.

We know our program worked fine before we added those 2 extra lines...so lets stop the program before it runs those two lines.

To the left of our source window we have a greyed out vertical bar. Let's put the cursor in that bar next to a line that contains some code. Then, press F9. This gets us a fat red dot, which indicates the breakpoint. Press F9 again to remove it later on.

breakpoint indicator

Now run the program again.

Don't panic....nothing bad has happened. At the bottom of your windows bar you can still see your Template program, as well as an open console window. But your Visual studio has become the windows focus. Look at your IDE window again:

hit breakpoint

Notice though that red dot now has a yellow arrow in it. This tells us that our program started, went through its set up process, and then when it arrived at the breakpount, it halted. Your program is now paused: now we have a chance to look at things.

Hover your cursor over the word tankY. You see that pop up line that appears?

This is the debugger giving you some information on the values related to tankY. It gives you its type, its address and more important is current value. But hovering over a variable name is not always a good way to view a variable we need something else. At the bottom left of your IDE you will see some tabs:

Visual Studio debugger tabs

The most important of these is the Autos window, this keeps track of any global variables that are currently in scope as well as local variables.  Ignore the this for now, we'll explain this when we talk about classes.

This window allows you to keep an eye on variables as they are changed by each line of code. Good, we have stopped our program and we're keeping a eye on our tankY variable, which looks ok, so..Lets look at our available debugging tools, the three most important are these icons:

debugging toolbar buttons

In order, these are Continue, Break (greyed out when in debug mode) , Stop, Restart, Show Next Statement and, the ones we are most interested in: Step Into, Step Over and Step Out. We'll start with the middle one, Step Over.

Click on that icon. We can see immediately something interesting happens.

Our yellow arrow has moved to the next line, ready to execute that and also did you notice what happened to tankY in our Autos window...it changed colour to red to indicate it had been changed by the instruction that just occurred.

Step Over has allowed us to execute this instruction:  if (tankY = 200)

Immediately we can see that tankY was changed to 200. Not what we wanted.. An "if test" should not be setting variables (note...sometimes this can be on purpose, but only very very strange people do this). By isolating that instruction we have been able to view the direct effect it has had on tankY. We should now be able to spot our bug, and normally we would stop the debugger and fix this mistake and re-run to test.

But for now lets examine what we can do with our debug commands. Our arrow is pointing at this line

    m_Screen->Print( "My Tank is at 200", 2, 2, 0xffffff );

meaning this is the next instruction that will be executed. Try pressing the Step Into command. Ok...Now we have gone to a totally new bit of code.

Pressing Step into will actually then take us into the Print routine. That's fine, but that routine is rather a large loop and stepping though ever single instruction will take us a long time. Here is where our Step Out instruction will helps us. We know the Print routine works...so pressing Step Out takes us magically back to where the routine was called in the game.cpp file.

When our program is running we can also stop it at any time using the Break all button, which looks like a CD pause button. If our program appears to get stuck in a tight loop, this can be a useful way to stop, but remember most modern programs run thousands and thousands of instructions each loop, and the Break All button will stop it at the exact instruction it is at when you press the button. We can continue at any time using the Continue (play) button. It is usually better to place breakpoints in code at points where you feel there is something that might need looking at.

Changing Values

Notice on the Autos window the tankY variable was coloured red after it was changed.

If you click on that value you can actually enter a new value; try entering 20 and then continue. You will see when it breaks again, your value of 20 is still there, but if you step over or into the

    if (tankY = 200)

command it will become 200 again. This proves to you that this is the command causing the problem and now you can stop debugging and change that line to

    if (tankY == 200)

This is your first taste of debugging, but it is something you will learn to do a lot of. All coders make mistakes and visually miss them, often the compiler will find them and print warnings or errors, but as you saw here, not all. So being to execute one instruction at a time and viewing the result is important. Of course it is also possible that the code is perfectly correct and compiles and runs, but does not actually do what you think it does. These kind of bugs are much harder to locate, but seeing the impact they have as they operate helps.

Assignment

Experiment with your debugger. Debugging skill comes from practice, add some features and functions to your tank demos and use the debugger to make sure things are happening as you expect them. Continue with the next tutorial when you feel comfortable with debugging.

0 Replies

Please log in or register to post a reply.

No replies have been made yet.