Thursday, October 21, 2010

Character 8-Directional Movement

Eight directional movement is where the character can move in any of the following either directions: north, south, east, west, northeast, northwest, southeast, and southwest. This is a common top-down RPG style movement. Of course each game is free to modify and create it's own type of movement. For instance the classic game Asteroids, your ships movement was propelled by a rocket in the rear of the ship thus it always moved you in the direction your ship was facing for the time you applied thrust. You could turn left and right rather quickly but forward momentum always kept carrying you in the same direction. Momentum and friction are used commonly enough in movement it will be worth covering at some point.

In order to make 8 directional movement using the previous Basic Character Movement snippet, some pretty small changes need to be made. It isn't much and you possibly already know what those changes are, or have made them yourself if you've messed around with previous snippet.

So we are already capturing the keyboard state for the keys we care about and they are all the arrow keys and in order to do 8 directional movement we only need to know whether those keys are being pressed or not.

// 8 directional movement, n,s,e,w,ne,nw,se,sw

  // direction variables used to determine whether to move the block in
  // either the x or y directions.
  int dx = 0;
  int dy = 0;

  if (up) {
   dy = -1;

  if (down) {
   dy = 1;

  if (right) {
   dx = 1;

  if (left) {
   dx = -1;

  // move the block by multiplying the amount of time in seconds that has
  // passed since the last update by the speed constant and by the change
  // in x or y directions which will either will result in += 0 or
  // dt * speed negative or positive.
  basicBlock.x += dt * speed * dx;
  basicBlock.y += dt * speed * dy;
As you can see above the difference between the previous snippet and this one is that in the previous update code only one of the if statements would be handled and so if dx was non-zero then dy would always be zero which means no movement in the y direction. Now we allow dx and dy to both be set to anything depending on the arrow keys that are currently pressed.

So here is the snippet for you to play around with:


Tom Norman said...

Won't this cause the block to move faster when moving on an angle?

MorbidMorvick said...

You are absolutely correct this code will cause the player to move faster on an angle. What I didn't include here was using a normalized vector to instead of dx,dy.

So you would put dx,dy in a Vector and you would have something like

Vector v = (new Vector(dx,dy)).normalize();
v = v.mult(speed*dt);
basicBlock.x += v.x;
basicBlock.y += v.y;

Or something to that effect. I kept the code simple so I didn't have to include a vector class though it is a simple class. You could also change the dx, dy to pre-calculated normalized vector coordinates in the case the player is moving on an angle.

if(dx != 0 && dy != 0) {
//approximate normalized coordinates
//keeping sign by multiplying
dx = dx * 0.71d;
dy = dy * 0.71d;

Note: insert above code right before the movement calculation in update(double dt) and change dx,dy to be doubles. It does act look and feel more natural. Thanks for noticing it Tom.

Post a Comment