Laying Out the Graphics Approach

I won't be able to do much more coding until the weekend.  So, I figured I should give a quick overview of how I'm going to approach the main graphics drawing routine.  I'll start high-level and work downward, then spiral back upward, and then back down a little bit before popping up into the atmosphere to wrap everything together.

It would be interesting to me to be able to approach displaying a game as if it were a live-action TV show.  You would have different sets (I'm going to call them "Game Spaces") for different sort of things.  Think about a normal local newscast -- you have the "main anchor desk" set, the "weather map" set, the "sports report" set, the "investigative reporter" set, etc.  For a game, this might translate into things like a main menu, a configuration menu, a high scores list, the pre-level briefing, the main gameplay space, the post-level results, and a game over screen.  Each set would have 1 or more cameras trained on it, and you would play the director ... "switch to set 1, camera 1" ... "zoom camera 2" ... "switch to camera 2" ... "prepare camera 1 on set 2" ... "move things around on set 2" ... "switch to set 2, camera 1" ... etc.

Now, when programming 2D games, I've always logically grouped my graphics into layers.  There's usually some sort of background layer which consists of your ground-level surface or a starfield or something else that is simply going to be behind everything else.  It may scroll around, but it will otherwise not really interact with anything else in the game and it's just there for your eyes and brain to have a backdrop on which to make sense of the rest of the game.  Then there is usually one or more layers of game objects (these are usually called "Sprites", and I don't plan to stray from that norm).  These layers might consist of a map layer and a layer for ships and weapons, etc.  Basically, I try to group the sprites that may interact with each other (and probably won't overlap in 2D space) into the same layer.

Let's use Gem Raider as a quick example.  Look at this screenshot (click it for a big version):

Example Screenshot of Gem Raider

In this game, I had 6 layers (starting back to front) ...

  1. The grid-like backdrop surface
  2. The "under the walls" explosion layer
  3. The "walls" layer for the main static map structures
  4. The "moving objects" layer for the player ship, the gems, and all of the weapons
  5. The "above everything" explosions layer
  6. The UI layer to show the score and the quick key listing

Each layer becomes, essentially, a collection of sprites.  Especially if you treat your primatives (drawn circles, rectangles, lines) and text as sprites, which I plan to do.  Sprites move around freely in game space.  Layers are drawn from back to front, and the current camera determines what part of that game space actually makes it to be displayed on the player's screen.

So, why put things in layers?  Why not just assign each sprite a "z" (or depth) value and allow DirectX to sort the order to draw things in?  Because I would like the programmer to easily be able to apply logic to all sprites in a layer at the same time.  Also, it will make for a logical grouping within which to breakup update and draw processes, if the game programmer wishes.  While Nimble2D will be designed to very easily draw everything on screen, it will still allow the programmer some capability to mix in some of their own drawing code if they wish (perhaps to render a true 3D object in amongst the layers somewhere).

Just as sprites will be able to move around, rotate and scale, cameras will be able to move around, rotate and scale/zoom ... and this will be reflected in how the sprites are drawn to the screen.  However, there will also be some "over layers" available within a game space that will not be impacted by the camera.  These over layers will be used to render UI components and messages onto the screen (after the camera shot is drawn) and always have them show up in the same screen location, no matter what is going on with the camera.

For most of what I'll be doing with Nimble2D to start, I'm just going to work with a single camera per game space, which will be drawing directly to the backbuffer.  However, I will also be keeping in mind that this system will eventually allow for multiple cameras in a game space, which will draw to their own render targets and those resulting graphics will be assembled onto the screen by the game space ... this will make it easy to do split screens for player-versus-player type games or games which might need to track multiple locations in the game space at the same time.

At the highest level -- the Nimble2D class itself -- each game space that is created will be tracked by the system.  A call to Nimble2D.UpdateAll will push update calls down through the camera, layers and sprites of the current game space (and every game space that is setup to do "background updates", which I will get into at a different time).  Drawing everything in the current game space to the screen will be done with Nimble2D.DrawAll, and switching between screens will be as easy as setting a different game space as Nimble2D.CurrentGameSpace.  As mentioned, there will also be finer-grain controls available to allow the programmer to update and draw just the pieces as is needed.  This also sets a nice framework for easily allowing full-screen fade-in and fade-out and other fun stuff.

For now, let's put it all together with this graphic of a single game space:

Nimble2D Game Space Visualization

It shows multiple layers resulting in a collection of sprites within the game space.  A camera presents a portion of the game space to the screen.  And over layers are added to give the player a single frame of the game.

2D game programmers will need to shift their thinking a bit from managing things within the scope of "screen space" to managing things within "game space" and grouping those things into layers ... and to how they wish to position the camera to show the game to the player.  (This also presents a programming challenge for the NimbleInput class -- giving mouse coordinates in both screen and game space ... but that's exactly where a library like this is supposed to make things easy on the game programmer, right?)

There is a lot of class skeletons and methods to get into place just to draw some simple sprites on the screen.  But once those are in place, the actual game code writing should become much easier, and we can then start fleshing things out to add value quickly.

-Matt

Published Thursday, January 24, 2008 12:33 PM by MattWorden

Comments

No Comments