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

Introduction

So you've got the beginnings of a tile engine. You've got your world scrolling across the screen in 16-bit color, complete with animations and anything else you decided to add on your own... but it's a pretty lonely place so far, isn't it? Today we're going to fix that problem by going over an easy way to implement the game's main character, along with some NPCs to keep him company. I'll show you how to get your world scrolling around the character so he stays in the middle of the screen, how to configure NPCs, and how to work them into the function you already have for drawing the map. When all is said and done, we'll have a nice start on an RPG (or other tile-based game) that is easily expanded upon. As usual, I'll have a complete code example for you to play with.

Throughout this article I'll be referring back to the basic tile engine we developed back in article #8, so if you haven't read it, and you haven't created a tile engine of your own before, go back and look over article #8 so you can follow along. Aside from that, all you need is a working knowledge of DirectDraw, the all-powerful Visual C++ (or one of those other ones), and some artwork to use. Ready to breathe a little life into your game world? Let's go!

Keeping Track of Characters

As usual, before we can go about getting something to move around on screen the way we want it to, we have to come up with a logical way to represent it in memory. Naturally, player characters and NPCs (non-player characters) are going to be represented somewhat differently. For instance, NPCs will need some flags or even a script assigned to them that describes how they move and act, whereas player characters do not, because they will be controlled by whoever's playing your game. Similarly, unless you're making your NPCs very complicated, they won't need a lot of the details that go into your player characters. For instance, non-combative NPCs don't need a number of hit points, a list of available spells, or a value for dexterity in a fight.

This leads to a little bit of a problem: what happens when we want to start moving NPCs and player characters around? Are we going to have to write one set of functions for player characters, and another set for NPCs? Obviously we don't want to do that. You C++ people should be thinking about a Character base class right now, and child classes called Player and NPC, or something similar. For those of us using C, we can do much the same thing by nesting a structure. That is, we'll create a struct for player characters and a separate one for NPCs, but each one will include a common struct that contains movement data. This might be a little unclear right now, so let me show you an example of such a structure, and we'll take it from there.

typedef struct CHARMOVE_type
{
  int xTile, yTile;        // character's current location
  int xOffset, yOffset;    // offset from tile location in pixels
  int xMove, yMove;        // number of tiles character is currently moving
  int nFace;               // direction character is facing; takes FACE_ constants
} CHARMOVE, FAR* LPCHARMOVE;

#define FACE_SOUTH 0
#define FACE_NORTH 3
#define FACE_EAST  6
#define FACE_WEST  9

All right, so what is all this stuff?

int xTile, yTile: As you've probably guessed, this will be the character's current location in tiles. These values will always be at least zero, and less than the size of the map in tiles. Furthermore, when a character is in the process of moving from one tile to another, these variables will be the coordinates of the tile the character is moving towards, not the tile the character is coming from. The reason for this will become clear later.

int xOffset, yOffset: Characters won't always be standing directly on top of a tile. When they're in the middle of moving from one to another, we'll need these offsets to track their exact location in pixels.

int xMove, yMove: These values are the number of tiles the character is set to move. For player characters these will always be -1, 0, or 1 (depending on direction); but for NPCs, whose every movement is not being controlled by an input device, the program may want to make them move greater distances at once. If xMove and yMove are both 0, the character is standing still. If xMove and yMove are both nonzero, the character is moving diagonally somehow. This will only happen if you allow eight-directional movement in your game. I didn't do that in Terran simply because there's no way in hell I can draw a half-decent character as viewed from a 45-degree angle. :)

int nFace: This simply keeps track of which direction the character is facing. Why, you ask, did I use 0, 3, 6, and 9 for the direction values instead of 0, 1, 2, and 3? Well, you'll understand when you see how I've set up the character image files we'll be using.

From here we might want to get started on structures for the whole player characters and NPCs, but I'm going to largely leave that out for now because all we'll really be dealing with is movement. The player structure would normally have all sorts of things in it like what level the character is on, what items he's carrying, what spells he can cast, and all kinds of other things. The NPC structure should have flags that determine how NPCs will be controlled. For now, I'm just going to leave those out and we'll use some kind of default values. Once we learn how to manipulate that, I'll show you what you can do to individualize your NPCs a bit. But for now, we'll just use these rather pointless structures:

typedef struct PLAYER_type
{
  CHARMOVE move;
} PLAYER, FAR* LPPLAYER;

typedef struct NPC_type
{
  CHARMOVE move;
} NPC, FAR* LPNPC;

Now that we've got two structures serving no purpose other than to differentiate between a player and non-player character, let's go on to seeing just how we get them moving around in our game.





Next : Character Image Files