After reading this great article by Jamie Fristrom, I got to thinking about how one should organize their exception handling in an XNA game. Since there are huge domain differences between an XNA application and a traditional business application, most of the exception handling texts out on the web right now may not offer the best advice.
In the traditional application world, exception handling is all about grace under pressure. Sure the app has been tested time and again, but surely at some point there will be an unexpected failure somewhere. Typically this will be with an external resource such as a database, access to a network share, or a web service. In this case, these external dependencies are well known at design time and developers can code for their eventual failure.
When you start talking about games though, the landscape is usually a little bit different. There aren’t usually as many external dependencies as there are complex subsystems. Of course, there are the obvious game data storage (ie. file IO), and network subsystems. But by and large, your main offenders will occur right at home in your own AppDomain.
In a game, your error handling will usually be with the express intent of helping a developer find the source of the bug as quickly as possible. In a small team, the developer will usually be running the game with the debugger attached, and will be able to make adjustments on the fly. However, what if you achieve the dream, and all of a sudden find yourself with funding and a team. Now the situation is more complex … especially when non-developer QA members enter the picture.
I’m not sure I have the answer (I know, so helpful ). But I do know that many .NET developers, even those that have been using the tech for years still don’t understand how to properly use exceptions. The biggest issue is often that either no exceptions are thrown/caught at all, or they are thrown far too often.
If your game has any external touch-points such as networking … then any and all operations on that external resource should have error handling with the assumption that it will fail at some point.
Internal subsystems such as animation libraries, physics engines, and AI modules should also be thought of as a black box resource. As far as your game is concerned, that call to physicsEngine.Update() could fail with the most obscure rotational flim flam error. You should structure your error handling to properly report the error to the user/player in a proper fashion such as debug text on the screen, or writing to a log file. All without affecting the main execution and rendering of the game.
Conversely, the above paragraph assumes that subsystems are properly structured to throw useful exceptions if there is some error state instead of just allowing bad input to cause some unrelated error (NullReferenceExceptions are usually a sign of this). This can be achieved by input validation … make sure you are in a valid state before continuing. Once you have identified invalid input, or an invalid state … you should throw a custom exception. Much has been written about this, but is neatly summed up here:
If you design it well, a malfunctioning subsystem shouldn’t affect the other subsystems. For example, if there’s a physics engine error, the rest of your game should continue rendering. If there’s an error loading a texture, you should probably load a default texture.
In each case, the game will handle the issue very gracefully; while at the same time notifying the user of the issue, and continuing execution. If this mantra is followed, it could allow artists to continue working with a certain build, even if there is a minor bug. This reduces stress on the developers because they don’t have to stop what they’re focusing on to fix a little bug that is stopping the artists from testing their content in-game.