Thursday, January 11, 2007

XNA's LoadGraphicsContent API, Part 2

So, after learning about XNA's LoadGraphicsContent API, an interesting question pops up as soon as you go to implement your own DrawableComponent - why is LoadGraphicsContent a protected method on components? How do I make sure it loads and unloads it's graphic objects properly?

The answer is "You don't have to". DrawableComponent is a sneaky and underhanded beast. It stealthily calls it's own LoadGraphicsContent method the first time during Initialize(), and then subscribes to the device reset events just like your Game object does. It calls LoadGraphicsContent or UnloadGraphicsContent in response to these events. This knowledge comes in handy if you try to contain components outside the Game object.

Friday, January 05, 2007

XNA's LoadGraphicsContent API

A friend of mine was a little confused about the best way to use XNA's LoadGraphicsContent API, so I thought I'd try to clarify it a bit here.

In general, your XNA Game object (or DrawableGameComponent object) will experience the following calls:

  1. Constructor
  2. Initialize()
  3. LoadGraphicsContent()
  4. Update / Draw repeatedly
  5. UnloadGraphicsContent()
  6. (maybe) goto 3
  7. Dispose()

In your constructor, you don't want to do much of anything. Assign values to things that aren't allowed to be null later, and maybe cache some constructor parameters into private fields of your object. Constructors in C# as a rule should avoid throwing exceptions. Try not to call any system APIs or anything that uses a resource, since that's a good way to encounter an exception. You can and should set your graphics preferences on the graphics object here.

In Initialize you have a lot more freedom. Your graphics object has been initialized and you should have a valid device. This is a good place for all the object creation and system calls that you wanted to make in your constructor. Don't load any Textures or Models yet though.


Load your Textures and Models in LoadGraphicsContent instead. This will get called every time the graphics card is reset (e.g. if the application moves from one monitor to another) and if you load a Texture in Initialize you'll be in for a nasty surprise after the device resets and you didn't reload it in LoadGraphicsContent. This is also where you want to create new RenderTargets.

UnloadGraphicsContent gets called when the device is being reset, or your application is ending. If you've loaded anything that needs explicit disposal, do that here. You'll notice the boilerplate telling the Content Manager to dump what it's loaded. If the device is being reset this call should be followed by a LoadGraphicsContent with the new graphics device settings.

You will rarely need to override Dispose. If you load something in Initialize that requires disposal you should do it here.


Update: One thing I forgot to mention about Initalize - if you are making a
GameComponent, you don't want to make any assumptions about whether you are
going to be drawn or receive updates soon. It could be a while between the
time an application initializes a component and when it actually gets to update
or draw. Some of the XNA documention samples do things in Initialize they probably shouldn't - for example, one of the audio
samples plays a sound in Initialize (that gaffe in the docs is my
fault, actually). While you can get away with that in a Game object it's a
bad habit in general.

Update2: If you want to control when LoadGraphicsContent is called, call Initialize on your Game's base class.

Labels:

Thursday, January 04, 2007

How I spent my Christmas Vacation

I've been working feverishly every night and weekend on my book. The first step is to do the code for the second section of the book, that introduces 2D programming concepts. To illustrate sprite programming I've created a game I call "Velocity" where you pilot a spaceship through rings while avoiding asteroids and the treacherous gravity wells of planets. I'm not much of an artist, but here is a screenshot of the game working on the test map (I plan to make one decent map to ship with the book). Click on the graphic for the larger version.




I may get a chance to improve the art before the book is finished (Mars and the asteroid Gaspra courtesy of NASA, but the ship and the ring are my fumbling attempt at art). I'm also doing 2 more versions of Velocity: one as a "2.5D" game and one as a 3D game from within the ship's cockpit.

Labels: ,