GAME 1024: Advanced Game Programming

24
GAME 1024: Advanced Game Programming Lesson 4: Debugging Is As Easy As 01, 10, 11 By Kain Shin

description

GAME 1024: Advanced Game Programming. Lesson 4: Debugging Is As Easy As 01, 10, 11 By Kain Shin. Quiz. What’s your full name State TWO reasons to make your program data driven What’s one reason to use an INI file over XML? What’s one reason to use an XML file over INI? - PowerPoint PPT Presentation

Transcript of GAME 1024: Advanced Game Programming

Page 1: GAME 1024: Advanced Game Programming

GAME 1024: Advanced Game ProgrammingLesson 4: Debugging Is As Easy As 01, 10, 11

By Kain Shin

Page 2: GAME 1024: Advanced Game Programming

Quiz1. What’s your full name

2. State TWO reasons to make your program data driven

3. What’s one reason to use an INI file over XML?

4. What’s one reason to use an XML file over INI?5. What is the difference between a function pointer and a

functor?

6. Give an example of a situation where you would want to use either a function pointer or a functor.

Page 3: GAME 1024: Advanced Game Programming

Bonus C++ Topic: Templates Definition: special code (classes/functions) that can operate

with generic types How? The compiler will create the explicit version of your

generic template AS NEEDED. “As Needed” means templates do not exist in the exe unless

something in code uses it Beware: Using a template with 100 different types is like

writing 100 different explicit pieces of code for that type as far as exe size is concerned.

Examples of templates already in use are STL and Boost

Page 4: GAME 1024: Advanced Game Programming

Template Function Example Template Function Declaration:

template <class T>T GetMin(T a, T b){

return a<b ? a:b;}

Template Function Usage:int minimumInt = GetMin<int>(10, 24);

T is of type “int”, which means the return value (minimumInt) as well as the a and b parameters (10 and 24) must all be of type “int”

Because “a<b” is used in the template, that means that whatever type T is needs to have operator< defined for it. So this code would not compile if I used a custom class in place of T that did not have “operator<“ defined.

Page 5: GAME 1024: Advanced Game Programming

Template Class Example Declaration:

template <class T>class cPair{public:

cPair(T v1, T v2);bool operator==(const cPair& rhs)const;

private:T m_v1;T m_v2;

};

template <class T>cPair::cPair(T v1, T v2): m_v1(v1), m_v2(v2){}

template <class T>bool cPair::operator==(const cPair& rhs)const{

return m_v1==rhs.m_v1 && m_v2==rhs.m_v2;}

Page 6: GAME 1024: Advanced Game Programming

Templates Continued Template Class Usage:

cPair<float> myFloatPair; Unlike a normal C++ class, template classes have restrictions on the class declaration being

in a separate file from the class implementation. You can do it, but the method is messy and it’s just not worth it.

You can have as many generic types as you want in a template. For example, you could do something like this….template <class X, class Y, class Z>

You can even specify an explicit type in your template argument. Like this…template <class X, int i, float f>

Remember that you don’t always have to pass in int or float as the explicit type for a template. You can use a complex type such as “cEventID” as long as cEventID has the proper functions defined that are needed by the template

Think of templates as a syntax that tells the compiler to “copy this code, but replace the placeholder template parameters (like T) with my explicit parameters (like int)”

Page 7: GAME 1024: Advanced Game Programming

Kill Your Bugs! Definition: When something doesn’t work as intended (crashes or acts “wrong”) Debugging is where the “Scientist” in “Computer Science” kicks in. The person

debugging is playing the role of a detective. Debugging Workflow

Identify the Bug Isolate the Source Isolate the Cause Determine the Fix Execute and Test the Fix

Things to Debug… Algorithmic Error Memory Leaks User Error Bad Data Etc.

Page 8: GAME 1024: Advanced Game Programming

Level 1: IDE Tools Call Stack Breakpoints Watch Windows Setting/Stepping the Instruction Pointer Disassembly Remote Debugging

Page 9: GAME 1024: Advanced Game Programming

Level 2:Tools You Write In Game Code Special Debug Visualizations (i.e. Physics

Hulls or Camera “Bread Crumbs”) Log Files Output Messages Asserts User Dialog Boxes Stuff Related to a Memory Manager

Page 10: GAME 1024: Advanced Game Programming

Level 3: HARDCORE!!!Using A Server App As A Debugger Communicates with the main app through TCP or UDP Visualizes the world in a data-centric manner as opposed to

graphics-centric… like Neo inside the Matrix! Great for debugging apps on one or more separate machines

(Like multiplayer deathmatch, MMOs) Great for visualizing and setting data that would be too messy

to tweak in the main app (such as AI states) Lots of logging…. Potentially able to play back recorded

events to simulate a recorded crash

Page 11: GAME 1024: Advanced Game Programming

A Note About Fullscreen Debugging It Sucks, try not to do it unless you have a second

monitor If you have only one monitor, run in windowed

mode It is possible to have bugs that only happen in

fullscreen mode. If this is the case AND you can’t get a second monitor, then use techniques that don’t interrupt the program (log files, output messages, remote debugging, stand-alone app running on another machine)

Page 12: GAME 1024: Advanced Game Programming

Detecting Memory Leaks What is a memory leak: It is when a heap allocation is not deallocated

when the program exits. The classic case is when a pointer gets orphaned.

A custom memory manager is the best way to detect memory leaks. We will cover this in a later lecture.

Visual Studio’s C Runtime Library Offers Three Functions that access the special debug heap that gets used when you run from the IDE: _CrtSetDbgFlag( int newFlag ) – Sets the behavior of the debug heap.

You typically use “_CRTDBG_LEAK_CHECK_DF” to get a dump of any leaks upon app exit

_CrtCheckMemory() – Runs a check on the debug heap for any orphaned memory

_CrtDumpMemoryLeaks() – Reports any leaks to stdout

Page 13: GAME 1024: Advanced Game Programming

_CrtSetDbgFlag Usage Example#if defined(_DEBUG)# define NEW new(_NORMAL_BLOCK, FILE, LINE_)#else# define NEW new#endif

#include <crtdbg.h>

void main(){

int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);

// always perform a leak check just before app exits.tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;

CrtSetDbgFlag(tmpDbgFlag);

cGame game;

bool playGame;do{

playGame = game.Update();}while( playGame );

}

Page 14: GAME 1024: Advanced Game Programming

Watch Windows Lets you see the value of any variable or

memory address Only works if debug information is available,

which it should be by default in DEBUG builds. You can do this in RELEASE builds, too, if you set it in your IDE

Only updates when program execution is paused

Page 15: GAME 1024: Advanced Game Programming

Using Asserts Pauses code execution if evaluated to false, but only in debug

mode Usage:

#include <assert.h>…assert(false);

Useful Trick:assert(false && “Helpful message here”);

Page 16: GAME 1024: Advanced Game Programming

Breakpoints Definition: Guaranteed to pause program execution

when it hits the set condition Visual Studio: F9 or click on area to the left of the target

code The condition is commonly “when execution hits a

specific instruction in code” The condition can be “when a certain memory

address changes” Can use the watch window while execution is paused

Page 17: GAME 1024: Advanced Game Programming

Stepping/Setting the Instruction Pointer You can make code execute one line at a time

Visual Studio: Debug->Step* Menu or F10/F11 keys You can set what line of code executes next

Visual Studio: right-click -> “Set Next Statement” This may be the single most helpful debugging

technique at your disposal

Page 18: GAME 1024: Advanced Game Programming

Call Stack Only active when code execution is paused

(assert, breakpoint, access violation crash) Lets you know where current execution is in

relation to the codebase When you have a problem in code and need

to communicate with another programmer, show them the call stack at the very least, or else it will be difficult to help you

Page 19: GAME 1024: Advanced Game Programming

Log Files An easy implementation is “fprintf(stderr, …)” as seen in the class project,

BUT… If you want more control, then you will need to wrap your log functionality into a

proper log file class that a program can properly append to, wipe, or create a new dated version as needed.

Reasons to wrap log functionality into a class instead of using stderr: Can use more than one log file for different systems Probably want log entries to be automatically timestamped Could be written in XML for “smart analysis” by another application The class can display logged info as an Output Message while logging

Log files should output to a temp folder so that people don’t accidentally think it is needed for the install

Page 20: GAME 1024: Advanced Game Programming

Output Messages Shows Up in the IDE and/or Custom User Tool within a

special output window Usually displays information that goes to a log file. It is still

useful because people can watch this window while the app is running instead of checking the log file every X seconds

With Visual Studio, you can use “OutputDebugString” to get your messages into the IDE’s output window

Page 21: GAME 1024: Advanced Game Programming

Remote Debugging Definition: Attaching your IDE to an external exe on

another machine You would do this if developing on a console (PC to

console connection) Also useful for debugging an exe on another

person’s machine (like a non-programmer) Could be used to debug something that only happens

in fullscreen on a system with only one monitor

Page 22: GAME 1024: Advanced Game Programming

Putting It All Together You get an access violation crash… What Do You Do?

1. View the call stack to see if there is any place in the stack that you should dig into

2. Drag variables into the watch window to see their values3. If that is still not enough, place a breakpoint in a key location to see

what you’re getting and try to reproduce the crash4. From the breakpoint, use the step functions to step the code one line

at a time, checking your watched variables at relevant steps5. Place asserts in code to catch bad things as they are happening6. View log output, set the instruction pointer, be like the Batman of

bugs, etc…

Page 23: GAME 1024: Advanced Game Programming

Your Class Project In Milestone 1: “#define your own versions of “new” and “delete”. Call

them NEW and DELETE, respectively. For now, leave them as the default new and delete. You’ll be writing a custom memory allocator eventually.”

Why do I make you define your own “NEW” and “DELETE” in all caps instead of redefining “new” and “delete”? Because you want to use the caps version to get the benefits of whatever memory management code you write without name-colliding with another library’s use of “new” and “delete”, which may have been redefined by them in the same way, but without the upper case.

In Milestone 2: “Logging/Debug Output: Make sure all notable occurences are logged in a log file and outputted in the debug window”

You will need to write a cLogger class that takes strings you send in and spits it out within the IDE’s Output window AND a file specified upon construction of the cLogger object

Page 24: GAME 1024: Advanced Game Programming

Final Thoughts… You get better at debugging as you gain programming

experience and a deeper understanding of how the hardware works

There is a lot of material out there that goes deeper into debugging than this lame PowerPoint presentation.

Your debugging methods will vary depending on the hardware you use

Sometimes, a really tough bug becomes an easy bug after a full night’s rest

Bugs will happen: You will never be a good programmer unless your debugging skills are decent, at the very least