Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
70 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Introduction
 Character Image
 Files

 Checking for
 Movement

 Collision Detection
 Animation
 NPCs and Random
 Movement

 Ordering Characters

 Printable version
 Discuss this article
 in the forums



The Series
 Beginning Windows
 Programming

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 Introduction
 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks

Collision Detection

Collision detection in a tile engine like this one is so simple it hardly deserves such an important-sounding name. All we have to do is look at the map at the place to which we want to move. If there's an object there, movement is not allowed. If the spot is open, movement is OK. How hard can that be? Basically there are three things we must check:

  1. Has the character reached the boundary of the map?
  2. Is the character attempting to walk into a solid object on the map?
  3. Is the character attempting to walk into another character?

The first one is a complete triviality. The second and third and pretty easy as well, as long as we have a way to keep track of that information, which we do! For detecting objects on the map, we have only to look at our tileset, which is represented by the TILE structure we set up back in article #8. If you remember, each TILE has a value called bWalkOK, which is TRUE if the tile can be walked on, or FALSE for solid objects. And remember that we check layer 1 of the map, not layer 2, because layer 2 is the foreground. If we were employing a three-layer system like I use in Terran, then what I do is to check layer 2 first. If layer 2 has some graphic in it, that tile determines whether or not the space can be walked on. If layer 2 is empty there, I check layer 1.

For checking characters, we look at the main character and all the NPCs, to see if any of them are standing on that tile. This is why, when a character begins moving, we change their tile location immediately instead of waiting until movement is done. This way, walking onto a tile that another character is moving towards is not allowed, whereas walking onto a tile that another character is currently walking away from is all right. Now all we need is an array of NPCs so we can keep track of them:

LPNPC lpnpc[100];

I've allowed for a lot of NPCs here; change the array size to match what you're going to need. Or you can always use a linked list. Remember that we've got a data member in our map structure to keep track of NPCs and we could use that too; I'm declaring it here separately to keep things a little clearer. Finally, you'll notice that I've declared pointers to structures instead of structures themselves. Why would I do that? Well, it's because we're going to have to sort NPCs later on, and it's faster to swap pointers than to swap entire functions.

Anyway, now we can write a function that checks the validity of a space. We'll pass it an x and y coordinate for the space to check, and have it return TRUE or FALSE. Here she is:

int MoveOK(int x, int y)
{
  int z;

  // first check the map boundaries
  if ((x < 0) || (y < 0) || (x > mapdata.xMax) || (y > mapdata.yMax))
    return(FALSE);

  // now check if the main character is already there
  if ((x == player.move.xTile) && (y == player.move.yTile))
    return(FALSE);

  // check all the NPCs
  for (z=0; z<mapdata.nNPCCount; z++)
  {
    if ((x == lpnpc[z]->move.xTile) && (y == lpnpc[z]->move.yTile))
      return(FALSE);
  }

  // the tile itself is now the deciding factor, so just return that
  return(tileData[byMap[x][y][0]].bWalkOK);
}

If you're wondering where mapdata and tileData came from, go back and look over article #8. These variables were defined in the code example that came with that article; we're just continuing the example this time around. Now, the only thing you might be wondering about is, if we're using this function to see if the player can move somewhere, why on earth would we check if the player is already standing there? Well, we'll also be utilizing this function to determine movement for NPCs, so it's necessary.

Now all we have to do is add a call to MoveOK() in our previous code that checks for whether the player is moving the character around or not. I won't repeat the whole code block here, but here's what the code for moving in the -y direction would look like:

if (KEYSTATE(VK_UP) && (player.move.xMove == 0) && 
                       (player.move.yMove == 0) &&
                       MoveOK(player.move.xTile, player.move.yTile - 1))
{
  player.move.yMove = -1;
  player.move.yTile--;
  player.move.yOffset += 32;
}

And we're all set! Now the game responds to keypresses by first checking whether or not a player is allowed to move in that particular direction, then changes the player's location settings if appropriate. The only thing left is the character's visual representation on the screen, and so we move to animation.





Next : Animation