March 2009 - Posts

It's All About the Cameras

Organization of the Core

The structure of the Nimble2D library is based on the idea of a central "Core" object that contains references to all of the major component objects and gives a coordinated means for all objects to be able to work off the same hub. The organization structure looks like this:
  • Core - The main object and "central hub"
    • Log - A log file writing class
    • Trig - An instance of the "QuickTrig" class I've written about previously
    • R - A central instance of a random number generator
    • GameClock - The GameClock, based on the class I've written about previously
    • GameSpace - a list of GameSpace objects used to organize game objects
      • LayerList - a list of layers within the GameSpace, which control the order that game objects are drawn in and which cameras can "see" those objects
        • GameObjects - a list of objects on the Layer within the GameSpace
    • MainScreen - The access point into how things are drawn to the screen
      • TargetPictureBox - The picture box being drawn to
      • CameraList - A list of Camera Objects (these are the key to a lot of things)
    • Input - The NimbleInput class
      • RawKey - an array of the low-level key up/down values
      • KeyState - an abstracted value for each key to allow for testing of down, double-down (like double-clicking for the mouse), first time down and for "clearing" keys (reporting it being "up" until the user releases and re-presses the key)
      • Mouse - organization around mouse information, such as location on the screen, location within the current GameSpace, and left/mid/right button states
      • Action - a layer abstracted above key and mouse states to define a game action and the input states that will trigger it
        • Trigger List - a list of defined input states that will trigger the action
    • Sound - A class to control music and sound effects (not yet built)
The main way to use the library will generally go as follows: 
  1. Create an instance of the "Core" object
  2. Setup GameSpaces & game objects as needed
  3. Define Input Actions as needed
  4. Launch the MainScreen
  5. Set Cameras on GameSpaces
  6. Loop:
    1. Core.UpdateAll
    2. AI & Physics
    3. Core.DrawAll

Why is it "All About the Cameras"?

So, how does everything come back to the Camera objects?  The Cameras are what put a frame around the things being seen on screen.  This frame is what the Input class will use to translate screen coordinates into GameSpace coordinates for the mouse.  It will also be involved in the Sound class to determine stereo panning for dynamic sound location.  And it will cooperate with GameSpace Layers to determine what is actually drawn to the screen and in what order.

It does this by acting as a miniature backbuffer ... everything "in the Camera" is drawn to the Camera's buffer, and then all of the active Cameras' buffers are drawn to the screen.  The properties that are important to translating between GameSpace and Screen space are:

  • Height & Width -- The size of the Camera's buffer that will be drawn on the screen ... if the Camera is locked to the full screen, these will be the same as the MainScreen's Height and Width
  • ScreenX & ScreenY -- The upper-left corner of where the Camera's buffer will be drawn onto the screen
  • CurrentX & CurrentY -- The current position of the Camera's center point within the GameSpace

Translating "Screen Space" to "GameSpace"

Consider this sort of setup ...Example Nimble2D Camera Setup
  •  The main screen is 400 x 300 and 3 cameras are used:
    • Camera 0 - the "score board" area of the screen is drawing just layer 0 from GameSpace 0 and is not used to translate the mouse position
    • Camera 1 - the "Main UI" area of the screen is drawing just layer 1 from GameSpace 0 and is not used to translate the mouse position
    • Camera 2 - the "Game Play" area; it is locked to the full size of the main screen and *is* used to translate the mouse position

As the mouse is moved around the screen, its current screen position is stored within the Core.Input.Mouse structure.  Those values alone might work just fine in a lot of circumstances.  In our example, a user's interaction within the "Main UI" area of the screen would likely just use the mouse's screen coordinates to figure out if the user is over a button.

However, in a moving environment -- such as most video games use -- where the game play may be scrolling around the screen, it is much better to have some way to tell where in the GameSpace the mouse pointer is currently pointing.

To accomplish this, the NimbleInput class steps through each of the active Camera objects that have their "UseForMouse" property set to True.  If the Mouse's screen location is within the area of the screen that the Camera is drawing to, then it uses the Camera's current GameSpace location, its size, and the position it draws to the screen to calculate the Mouse's GameSpace X and Y values.

The code that does the work looks something like this:

Mouse.GameSpaceX = Camera.CurrentX - Camera.Width / 2 + (Mouse.ScreenX - Camera.ScreenX)

Mouse.GameSpaceY = Camera.CurrentY - Camera.Height / 2 + (Mouse.ScreenY - Camera.ScreenY) 

And with that, Nimble2D will provide easy-to-access information on where in your game world the mouse is currently located.

Posted by MattWorden | with no comments