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.Circle(position);
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!

Sunday, September 12, 2010

Taking out the Garbage

After adding lots of new enemies and systems to the game, I took a look at the performance on the 360. Performance with 2 players was terribly slow, so I thought I would write briefly about some of the optimizations I made to get it back to 60fps.

Firstly, using the XNA Remote Performance Monitor to gather some more detailed information I saw there was a garbage collection quite frequently. Digging into this with the CLR Profiler I noticed a few things allocating frequently per-frame. The 360 collects garbage every time 1MB is allocated, so reducing the allocation to less than 1MB during a stage would keep us free from any GC-related performance problems.

Firstly, the framerate counter was generating with String.Format(), which generates garbage objects. A few object allocations per frame adds up very fast, so avoiding this is vital to keep the next garbage collect away. Caching all the strings to only be recreated when the value changes removed most of the issues from the HUD.

Secondly, a GetMethod() call in the collision resolution was causing an allocation -- given the number of colliding entities this was generating a lot of garbage objects! A simple brute force method of caching collision methods in a Dictionary reduced the need to call GetMethod() more than once for any collision pair type.

The next target was all of the LINQ usage throughout the codebase. LINQ is significantly slower and allocates a few objects, so keep it far and away from anything running every frame.

Using C# and XNA you can easily generate alot of garbage without realizing it. The CLR profiler has a very simplistic interface, but can give you really amazingly detailed data. You can dig through allocations over time, view the entire heap with each allocation showed by type, and you can see who allocated any block of memory. Very useful!

Here is a post of the current histogram showing the allocations over a minute of entering the game and playing a little bit of a stage:

Allocation Histogram

The large noticeable allocations are Texture data, and a large Vertex Buffer and Sprite Vertex allocation by the XNA internal rendering system. Although this shows that alot of the previous unnecessary allocations have been removed, it still shows room for improvement.

The dictionary of cached collision methods is still rather large -- we can write something to iterate all game entities in the assembly and precache the collision map before the game starts.

Given that there are not so many textures in this game, we can pre-load all of them at the start of the game (and find a way to precache the XNA sprite vertex data too), to keep all those allocations together.

There are better ways to architect your game to never have these sort of GC problems, but if you just want to get things done fast then a few simple things like this can let you keep the GC at bay without spending all of your time writing things that aren't the game itself.

Tuesday, April 27, 2010

XNA4: BasicEffect optimizations


The soon to be released XNA4 (RC already available) contains some very nice optimizations to the supplied BasicEffect class:


Given this and the added flexibility of custom shaders and custom rendering for the BasicEffect class, developing games in XNA4 will be alot more feasible without requiring a custom renderer. 

This of course means more time to get the game polished and gameplay as fun as possible!

Monday, April 26, 2010

C#: Generated Code


Another post just to point out a nice link:


This post is fairly old now (2003), but still provides lots of useful information. It provides a good overview of what things cost in C#, by looking at the generated assembly code.

Overall, there aren't any significant surpises. Things seem to be fairly similar to C++. Instance function calls, basic variable manipulation, and simple math code is cheap and generates pretty much one-to-one assembly much like you can imagine C++ code does. 

In the same way, virtual functions and delegates are slow to call and should be avoided in performance-critical code much like C++. Memory layout and class internals are also fairly unsuprising, and structured as you would imagine; vtables are where you expect them, etc.

If you are comfortable with writing C++ and being aware of what sort of assembly code is generated, then you should be able to write C# code that performs well and doesn't give any nasty suprises.

Given that 7 (!) years have passed since that post, the runtime and optimizations should be significantly improved, so everything will be much faster and your generated code should contain alot of the sort of optimizations you can get from modern C++ compilers.

Sunday, April 25, 2010

Caching


This blog post is mostly just to share a link pasted by a co-worker:


It pays to be aware of the cache, especially when developing games for consoles. In the low-level code avoiding cache misses will be where most of your optimization gains can be realized. 

Having your data well structured for systems such as collision and rendering is of utmost importance for keeping things running fast. Just make sure you spend time on the right areas of your code, at the end of the day alot of your code will simply not need to be optimized to this degree if it is coded sensibly.

Wednesday, April 21, 2010

C#: Fibers


In the previous post, we looked briefly at the uses for fibers in relation to game code. Let's look at what this looks like in C# using yield, IEnumerable, and lambda expressions. We will need a CFiberManager class which handles updating and launching our fibers.

First we will examine the user code interface  we want to attain before we look at the whole implementation. We will make a sound player Play() function which only allows us to play a sound once every N frames.


// sound system example
public void Play(string name)
{
  if (registry.HasKey(name))
    return;

  SoundEffect sound = Content.Load(name);
  registry[name] = sound;

  int WaitFrames = 4;


  Fibers.Fork(() => {
            while (WaitFrames-- > 0)
                yield return WaitFrames;
            registry.Remove(name);
  });
}




Here we play a sound, and then add it to a registry which will prevent playing the same sound until 4 frames later. It would be good to also add some counts for tracking concurrent playing sounds, as well as minimum spacing to ensure the sound does not get spammed in certain gameplay situations, and to just sound 'right' with regards to spacing, even when lots of entities attempt to play a sound in a short time.

Here we can see the implementation of the Fiber manager:


Maybe one day we can see some nicer language support for fibers in C# without resorting to this IEnumerable trick!

Monday, April 19, 2010

Forking your game


Having used a scripting language with native fiber support (GameMonkey) with some custom modifications to provide in-language syntax for this, I found myself wanting a similar feature when making games in C#.

As an example, somecode would start out something like this:


// another enemy-based example
self.Shoot()


until someone requests 'can you just make it wait 1 second and then turn and shoot again?', or perhaps 3 times, or 4 times and then wait 2 seconds and explode. This sort of change without fibers will add a big mess of new members, tracking state, timers and sleep values, as so forth. After which may just end up being thrown away since it didn't 'feel' right.

Having native language support for fibers lets us do something like this:


fork {
  sleep(1);
  self.Shoot();
  sleep(1);
  self.Rotate( PI );
  self.Shoot();
  sleep(1);
  self.Explode();
}


and we can test it right away. The benefit here is that the code change is very very local and doesn't really impact any other behaviour of our entity.

There is no native C# support for this sort of fork'ing code, but with the yield statement and IEnumerable, we can implement something clever to make this work, which we will cover in the next blog post! :)

Friday, April 16, 2010

C#: Collection Initializers


Developing games requires countless amounts of properties and settings that often straddle the line between 'code' and 'data' quite akwardly. C# Collection Initializers allow very nice inline placement of these sorts of values.

Here is a snippet of some weapon data for a 2D top-down shooter:



new List() {
    new SWeaponData() {
        ReloadTime = 0.15f,
        Speed = 15.0f,
        Damage = 0.3f,
        Offset = new Vector2(0.0f, -10.0f),
    },
    new SWeaponData() {
        ReloadTime = 0.15f,
        Speed = 15.0f,
        Damage = 0.3f,
        Offset = new Vector2(0.0f, 10.0f),
    },
},


This sort of code/data is easy to modify and understand, and really just is an excellent fundamental language feature that you will miss using C++.

Keep in mind that this code runs -after- the constructors, so you can have default values in your constructor, and then on a per-instance basis override any of the values. Very useful!


// Instant variation!
Turret t = new Turret() { Texture = "MagicTurret", SE = "MagicShoot", Health = 20 };


Sensible defaults with the occasional case-specific override gives your code an enormous amount of flexibility.

Saturday, April 3, 2010

Variations


Having alot of unique entities in a game will make a game stand out as interesting and fun. Unfortunately there is never quite enough time to develop as much as you would like, so it is worthwhile to find ways to vary existing entities sufficiently with as minimal a change as possible.


It doesn't take a significant change to make an entity feel different and provide a different play experience. Enemies for example can be varied with an artwork change, and some small behavioural changes. Changing a texture, adding a simple variation of firing pattern, and changing projectile graphics will effectively create a new enemy while keeping the majority of the code reusable. 

There are lots of clever ways to design and code your game entities to allow code re-use and provide variations, but at the end of the day a simple old 'if' placed here and there in the code is often the most effective and flexibile solution. It's not worth abstracting every piece of behaviour and functionality, just keep the code simple and clean, and branch in the right places to make your entities new and interesting.

Game objects should be kept standalone where possible, so that they may be used in various places. When creating new entities, it can be very useful to just reuse some existing entity as a placeholder to get a feel for behaviour. This can be particularly useful for bosses, and designers will often ask things like 'can you make the boss shoot the foo-enemy bombs at this point?'. Bits and pieces of your game entities will end up in places you do not expect, so make sure everything is usable as standalone as possible.

And if all else fails, copy and paste it all. It's all going to change anyway, right? :) 

Monday, March 22, 2010

Properties and Stage Design


Well tuned gameplay requires countless iterations of testing, and very careful mashing of all values related to gameplay systems. When developing it is useful to keep in mind the accessibility of values affecting gameplay and ways to keep testing iteration time as low as possible. Aim for less than 1 second turnaround between changing a value and being able to test it.

Given a typical game with Stages, Enemies and Weapons, you want most of the values to be accessible to programmers and non-programmers. Enemies and Weapons will have typical values; health, reload times, damage values, ammunition counts, projectile speed, et cetera. Make sure everything relevant to the feel of the element is exposed in an easily-editable property.

Having a set of readily tweakable values is the first step. Following that you need to be able to put your game in a state where you can try them out to get a real feel for the changes. This must be kept to a very (!) minimal procedure. Even with a fast game startup time, loading a stage and playing 15 seconds to get to the 'test' area is something you must avoid where possible.

Be sure to have an empty stage ready into which you can place relevant items and have a good test zone to begin tweaking values. Keyboard shortcuts in your tools will be the key to making this work well. For creating real levels, be able to start the player from any point in the level to allow iteration of particular segments without re-playing irrelevant sections.

The first phase of development and tweaking will be done on the programmer side, and often just  through the code itself and not via properties. On the programmer side it will be easier to tweak behaviour and state directly. Think well about what properties will be worth extracting for later tweaking by designers. 

On the designer side, there will be alot of adjustment of properties based on usage in actual game stages. It helps to have a very short feedback loop between programmers and designers so you can make sure all the relevant properties are editable, and to get behaviour and functionality changes implemented quickly so designer-side iterative testing can be efficient.

It can be easy to have too much editable in the properties such that only the programmer who wrote the entity can understand what everything means and how it will impact the entity. Try to keep the internals internal, so you can change functionality and keep only things that are relevant editable on the design side.

Quick feedback loop between programmers and designers, editable properties and countless iterations of testing and tweaking are what really makes the difference between a functioning game element and one that feels good and fun.