Friday, October 1, 2010

Press Start to Debug

As a short follow-up to the previous post, I thought I would mention some other useful debugging-related features you can add to your codebase.

Firstly, splitting your game camera and viewing camera will let you track down lots of issues easier. Alot of games will not (should not) render objects off-screen, but if you cannot see off-screen are you sure this is happening correctly? Having a second camera which can be zoomed out above the 'game' camera will allow you to see exactly how far off the screen your objects are still visible, and when they are being deleted, et cetera.

You can use your debug primitives rendering to display the game-camera bounding box so you can see it clearly from your debug camera. You can also zoom in closely and make sure your objects are being rendered correctly, look for minor visual issues, and inspect your tiny particle effects to make sure they look correct and artifact-free.

To help with all of this, it is extremely useful to put proper debug pause support into your game. Have a key/button for pausing all of the game entirely, but continue rendering each frame (your logic is not being run in the render code, right?!). From this state you can move around with your debug camera and inspect things in their paused state.

Make sure you add a single-frame-step key to your debug pause system, it will be immensely useful for inspecting particle effects, checking object behaviour, and looking at game state before a crash/bug occurs.

Debug Rendering

There are many useful in-game debugging tools you can build to help track problems and be more aware of the details of things happening in your game. I'll cover a few useful techniques in this post you can try out.

Debug Primitives are on of the most useful tools you can build into your codebase. Being able to generate primitives easily will allow you to test new entities and debug existing behaviour much easier. You will want to be able to simply render the following primitives with the least amount of code possible: Circles, Boxes, Arrows, Lines and Text.

Since this is for debugging purposes performance does not really matter so much, focus on keeping the code required to render these primitives as painless as possible. The code should be callable anywhere and have an interface as simple as something like:

CDebug.Circle(position, radius, color);
CDebug.Line(a, b, thickness, color);
CDebug.Vector(position, direction);
CDebug.Text(position, string);

Provide lots of overloads to cut out all the parameters you don't care about so you can just dump something on the screen with minimal code. It is worth creating screenspace and worldspace versions of these functions!

Using these primitives you can generate debug displays for your other systems, such as rendering your collision boxes for objects, or displaying your collision quadtree.

A useful trick can be to use object memory addresses to generate a color, so you can do something like drawing a randomly colored box for all your GUI components to help visualize the real layout if the textures are not clean box shapes. Making these partially transparent will let you see the overlap of UI components and sometimes spot some unnecessary UI parts floating around.

Having all your entities renderable as a simple string is useful for tracking down invisible objects or offscreen objects. Finding an object seems to be alive but offscreen somewhere? Add a debug utility to render all your objects as strings and clamp to the edge of the screen. When you see a floating CBulletEntity text clamped to the edge but with no visible entity you know something isn't getting deleted properly.

Happy debugging!