When you look at most of the sample code that’s out there for doing 2D XNA games you may notice that there is a tendency to sprinkle in the drawing code all over the place. Simple samples/tutorials will put it directly in Game.Draw(…) while more complicated projects usually have it inside the game ‘entities’.
In this post, I’d like to present an alternative method that has a number of advantages. I call this ‘The Retained Sprite Method’. This isn’t a new concept, and there is nothing magical or complicated about what I’m going to show you, but it will go along way to help clean up your code and make more reusable ‘engine’ components.
What is the retained sprite method?
The idea is that you put all of your drawing code in exactly one place. I’ll call this the DrawingContext. Furthermore, your game entities do not typically use the DrawingContext to draw anything…only Sprites do. A Sprites is a ‘dumb’ (no Update) object that describes what/where to draw. Your game entities (player, enemy, boss, etc) do all the ‘thinking’ (Update) and create/retain sprites in a sprite tree. Each frame the entities do not have to do anything to draw the sprites, just being in the tree means the entity is drawn.
Lets look a class diagram:
What you see above is a very simple retained sprite system. This system supports two types of Sprites.
FrameSprite will draw a single image to the screen (a Frame describes the Texture, SourceRect, and SpriteEffect to use).
TextSprite will draw a string of text to the screen using a given font & alignment.
You can imagine how such a system could be extended. In my game engine I have other types of sprites like AvatarSprite, AnimatedSprite, MovieSprite, etc.
You can then build higher level components on top of this. For example, layout/controls framework uses the sprite tree for it’s rendering.
Some of the advantages of doing your drawing this way are:
- You don’t have spriteBatch.Draw code sprinkled all over your codebase. It’s all in DrawingContext, so you can upgrade/port to new rendering systems easily.
- Your game code is more declarative (read ‘clean’), because you’re describing what to draw, instead of how to draw it.
- Because it’s more declarative, it naturally lends itself to using an animation system as described in previous posts.
- Things like layers, multiple cameras, culling, etc become much easier when you retain a sprite tree.
- Sprites can have Children, so doing relative motion is trival. Whenever a parent sprite moves/rotates, all children are also moved/rotated. The same applies to Scale/Color.
The sample code below shows how to use this sprite system, and as a bonus I added plenty of animations to show how powerful the combinations of a retained sprite tree with an animation system can be.
If you’re not convinced that this is the way to go, then I invite you to re-create this sample without using the retained sprite tree & post it in the comments.