2-Dimensional Coordinates


  -=======================================-
  -=== VGASteve's Programming Articles ===-
  -=======================================-
  - By Steve Swan                         -
  - (C) Copyright 2000                    -
  - All Rights Reserved                   -
  -----------------------------------------

  Todays's topic : 2-Dimensional Coordinates


  Welcome to this issue of VGASteve's Programming...  In this article
  I will be explaining the three main 2-D coordinate systems involved
  in a side scrolling game.  First, what IS a side scrolling game?  A
  side scrolling game is a tile-based game where the player views the
  world from a side, as the world scrolls in all directions.  This
  means that the player can only see a fixed amount of space in front
  of him.

  Examples of side scrolling games include Commander Keen, Jazz Jackrabbit,
  and Super Mario Brothers.

  The levels for these games are stored as a grid.  Each grid square
  represents a tile, or bitmap of fixed size.  Common sizes for these
  bitmaps include 16x16 pixels and 32x32 pixels.  The artwork for a
  level is split into bite-sized chunks this way.  One tile could be a
  piece of wall, while another tile is the right side of a ledge.  One
  tile could be a corner of a large window, while another could be a
  chunk of wall with a torch mounted on it.

  Anyway, this gives the level designers the flexibility to decide where
  they want to put windows, torches, walls, stairways, etc.  The grid
  which holds the level can have basically any dimensions you want.  Each
  entry in the level grid is a number which references a tile, or bitmap,
  stored in an array of bitmaps.  Because there are generally fewer than
  256 different tiles in a good sized level, we can safely allocate a
  single byte (number range of 0-255) for each grid square.

  Now that we've had the overview, let's jump right in...  Here are the
  three types of coordinate systems used in a side scroller engine:

    - Grid Coordinates     
    - World Coordinates    
    - Screen Coordinates   

  Each coordinate measurement has an X axis and a Y axis.  To clarify these,
  consider the following diagram:

   0,0
    +------------------------------------------------------->
    |                                  Increasing X values
    |
    |
    |
    |
    |
    |
    | Increasing Y values
    |
    |
    |
   \|/

  The origin is at the upper-left hand corner, and the X and Y values
  increase as they move out.  This is the coordinate system used on
  computer screens.

  We've already seen a glimpse of the grid coordinates.  These coordinates
  identify a particular square on the grid.  The square in the very upper
  left hand corner of the level is square (0, 0).  The first number in
  parentheses is the X coordinate, and the second number is the Y coordinate.

  If your level is 64 grid squares across and 128 grid squares down, we say
  it's size is 64x128 grid squares.  The upper left hand corner is (0, 0),
  and the bottom right hand corner is (63, 127).  Note that we measure from
  0.

  World coordinates are measured in pixels.  They also have their origin
  at the upper-left hand of the level grid, but they can be used to specify
  an exact location on any tile.  The dimensions of your level in world
  coordinates are determined by the dimensions in tiles and the dimensions
  of your tile artwork.  If you have 32 by 32 pixel artwork, and your
  level is 64x64 grid squares, the dimensions in world coordinates
  are (32*64, 32*64), or (2048, 2048).  This means that the lower right
  hand edge of the level would be (2047, 2047).

  Here's an illustration of grid coordinates vs. world coordinates:


           --Tiles are 16x16 pixels--
  First numbers listed are grid coordinates.
  Second numbers are world coordinates.

  +--------+--------+--------+--------+--------+--------+--------+--------
  |(0,0)   |        |        |(3,0)   |        |        |        |
  |(0,0)   |        |        |(48,0)  |        |        |        |
  |        |        |        |        |        |        |        |
  |        |        |        |        |        |        |        |
  +--------+--------+--------+--------+--------+--------+--------+--------
  |        |        |(2,1)   |        |(4,1)   |        |        |
  |        |        |(32,16) |        |(64,16) |        |        |
  |        |        |        |        |        |        |        |
  |        |        |        |        |        |        |        |
  +--------+--------+--------+--------+--------+--------+--------+--------
  |        |(1,3)   |        |        |        |        |        |
  |        |(16,32) |        |        |        |        |        |
  |        |        |
  |

  Note that we are only looking at upper-left corners of the tiles...
  World coordinates let us address ANY pixel in the level grid.  To look
  in the MIDDLE of tile (1, 1), we would use (16+8, 16+8), or (24, 24).

  The game engine I'm currently developing, SmoothBore(R), uses world
  coordinates to keep track of where the enemies are because the enemies
  need to move smoothly, instead of jerking from tile to tile.

  Now to move on to the last coordinate system...  Screen coordinates are
  measured in pixels just like world coordinates are.  The difference is
  that they have their origin in the upper left hand corner of the SCREEN.
  When you are playing a side scroller, you will notice that the screen
  is constantly scrolling, and hence the origin of the screen is constantly
  changing.

  To keep track of where the upper-left hand corner of the screen is, you
  use World coordinates.  Hence, if your screen starts at (39, 47), and you
  have a Screen coordinate point (5, 8), the same point in world coordinates
  is (39 + 5, 47 + 8).  This suggests the formula:

    worldX = screenStartX + screenX;
    worldY = screenStartY + screenY;

  Also, to find the screen coordinate form of a given world coordinate:

    screenX = worldX - screenStartX;
    screenY = worldY - screenStartY;

  You can gather from the above that it is VERY important to keep track
  of the origin of the screen (screenStartX, screenStartY) in world
  coordinates.  This is, in fact, how scrolling is achieved; by moving
  these variables.

  How useful are screen coordinates???  VERY useful.  You have to translate
  enemy positions (in world coordinates) into screen coordinates in order
  to know where to draw them on the screen, or, indeed, IF you should
  bother drawing them at all...  For instance, let's say you have an sprite
  (another name for an enemy) who's position in world coordinates is
  (50, 80), and your screen origin is at (256, 430).

   +----------------------------------------------------------------------->
   | (50, 80)
   |  ++ Sprite
   |  ++
   |
   |
   |
   |
   |
   |         (256, 430)
   |          +---------------+
   |          | Screen        |
   |          |               |
   |          |               |
   |          |               |
   |          +---------------+
   |

  It's fairly obvious at a glance that the sprite shouldn't be drawn to the
  screen.  But how does your code know this???  Let's translate to screen
  coordinates:

    screenX = worldX - screenStartX;
    screenY = worldY - screenStartY;
    screenX = 50 - 256
    screenY = 80 - 430
    screenX = -206
    screenY = -350

  If your sprite is 32x32 pixels, then you wouldn't bother drawing him
  unless the his screen coordinate position was greater than (-32, -32).
  With a quick compare, the code above can rule him out of the picture...

  In summary, here's a table with the three different coordinate types:


   Coordinate:          Unit:           Origin:
   --------------------------------------------------------------------
   Grid Coordinates     Grid Squares    U.L. Corner of level
   World Coordinates    Pixels          U.L. Corner of level
   Screen Coordinates   Pixels          U.L. Corner of screen
   --------------------------------------------------------------------

  And here are some equations:

   worldX = gridX * tileSizeX           // Grid to World
   worldY = gridY * tileSizeY
   gridX = worldX / tileSizeX           // World to Grid
   gridY = worldY / tileSizeY
   screenX = worldX - screenStartX      // World to Screen
   screenY = worldY - screenStartY
   worldX = screenX + screenStartX      // Screen to World
   worldY = screenY + screenStartY
   screenX = (gridX * tileSizeX) - screenStartX    // Grid to Screen
   screenY = (gridY * tileSizeY) - screenStartY                       
   gridX = (screenX + screenStartX) / tileSizeX    // Screen to Grid
   gridY = (screenY + screenStartY) / tileSizeY                        


  That's All!
  Next Time : Hit Detection!

  E-Mail : VGASteve@yahoo.com




© Copyright 2001 by Steve Swan