The Old Method
The current methodology I'm using for grpahics is based on the same strategy I've been using for years. In this architecture I separate out system components into modules called "Graphics", "Audio", "Control" and so on, and all the game specific data and routines are stuffed into a single instance of a class called "World". I can't remember why I started calling this class "World" as it's a bit misleading - if the game were an RPG there would probably be a contained subclass called "GameWorld" or something similar along with other game related data within the World, but the name has stuck in my mind. Maybe I should go with something like "Universe" instead - but I digress.
The alogrithm for displaying stuff to the screen was very simple conceptually:
- The main game loop would call a Draw function in the game World.
- The World calls a Draw function on all the game object it contains (for example, a PlayField class), which in turn call Draw functions until it gets down to a primitive object
- A simple primitive object will in its Draw function call Graphics module functions that renders the object to the back buffer
- After all the World has drawn, the main game loop calls a Display function in the Graphics module which swaps buffers and displays the new scene
The downsides however can get annoying in complex games. Here's a few:
- Even with rendering functions like DrawSprite the graphics functions tend to closely mimic the underlying graphics rendering routines, meaning the game world objects have to understand the rendering algorithm.
- Every game world object has access to the graphics functions, although they are all localised in the Draw function.
- The game world has the responsiblity to render the objects in the right order.
- It's hard to use more advanced graphics techniques to accelerate the rendering as the graphics rendering code is all over the place.
The New Method
I'd like to try a new method for this 2D library that's a little more opaque to the game world. Under this approach the game objects do not have access to graphics rendering functions. Instead they contain their own Sprite class which hides all the details from them.
A Sprite will act like a black box graphics object that contains the rendering information needed to display the sprite to the screen. The game objects themselves can call methods from a Sprite object to position it in world or screen coordinates, set which sprite to display on the screen, set whether it is visible or not, set what depth or layer it is on, and whatever other rendering options I may want. The Sprite itself will contain whatever extra information it needs to give the renderer to display the sprite to the screen.
The big difference in the program flow that I'm considering is that the game World will not have a Draw function anymore. Instead the Sprites themselves will register themselves up to the Graphics module on creation. In a sense the Sprites belong both to the game World object that owns them and to the renderer. The Graphics module can keep its own ordering of Sprites (either internally or internal to the Sprites themselve) to speed up the rendering.
There are a few small drawbacks that I can think of at the moment:
- Firstly, I'm limited to sprites (and maybe coloured rectangles) only (until I can think of a way to get other primitives to work in this scheme). This isn't that bad a restriction for a 2D only system though.
- I'll still need some global access to the renderer; the Sprites need to register up at creation. This means I'll still need some sort of global or singleton graphics system deep within the engine somewhere, which may or may not be a bad thing depending which side you take on the Singleton Holy Wars that wage on the internet. However game world objects will only be interfacing through graphics related objects like Sprites.
- I also think I'll need Camera objects to tell the graphics system which part of the game world to display, so there will likely be more than just Sprites that interface with the Graphics system within the game World itself.
The nice bit about hiding all the information to render within the Sprites is that I can start off with something really basic, such as the immediate mode rendering that I'm presently using, but can easily switch to something more advanced by only modifying the internals of the Sprite class and the Graphics module, not by changing the interface with the World. I can play around with acceleration tricks by batching together sprites in ways that are totally hidden to the game code.
Of course most of these things will take me a while to get around to implementing; at the moment all I care about is the basic skeleton of the graphics module so I can get the framework down. I'm sure I'll make a lot of design mistakes in this first version but with this approach I think they won't be too hard to refactor in the next.
Sounds good, or just plain crazy?