SDL Player movement & animation glitch

Started by
12 comments, last by Khatharr 11 years, 2 months ago

Milcho i am looking for sprite artist and coders for my project since im looking to make it open source on github

Advertisement

Milcho i am looking for sprite artist and coders for my project since im looking to make it open source on github

I thought you were saying that your animation was too fast - and I assumed you had the correct sprites for the animation. I still think your actual animation should be done outside the keydown handling, but if your problem is with the animation sprites not being as you want them, then I can't help you.

i was not asking to help with sprite, i was just letting you know i might be making the project open source soon and thought you might have some interest in it!

im working on the animation at the moment

here some of the maps so far :)

First map

21b51m1.png

route connecting to the next city

1zxs4jm.png

and the Ember City that the route connects to

23s6hhl.png

I anticipated your animation speed problem when I was making my previous post but figured I'd wait until you asked. (It's the next issue to arise in the logical order of what you're doing here.)

Simply use an animation step that is a multiple of the number of your animation frame count and then select the frame by integer division. This is going to get progressively more difficult if you don't either rearrange your sprite sheet or else abstract the positioning so that you can refer to the direction and animation separately. This function is already really big.

Check this out:


enum DIRECTION {
  DIR_DOWN = 0,
  DIR_LEFT,
  DIR_RIGHT,
  DIR_UP,
  DIR_NONE
};

const int ANIMATION_FRAMES = 4;
const int ANIMATION_RATE = 15; //play with this number to control animation speed
const int ANIMSTEP_MAX = ANIMATION_FRAMES * ANIMATION_RATE;

DIRECTION dir4(Uint8* keystate) {
  if(keystate[SDLK_DOWN])  {return DIR_DOWN;}
  if(keystate[SDLK_LEFT])  {return DIR_LEFT;}
  if(keystate[SDLK_RIGHT]) {return DIR_RIGHT;}
  if(keystate[SDLK_UP])    {return DIR_UP;}
  return DIR_NONE;
}

DIRECTION direction = DIR_DOWN;
int animstep = 0;

static void player_movement(void) {
  //This should really be called from outside and handed in.
  //You want the same control state for the whole logical frame.
  Uint8* keystate = SDL_GetKeyState(NULL);
  DIRECTION dir = dir4(keystate);
  if(dir == DIR_NONE) {
    animstep = 0;
    return;
  }
  direction = dir;
  ++animstep;
  animstep %= ANIMATION_MAX;
  switch(direction) {
    case DIR_DOWN:  player_y += speed; break;
    case DIR_UP:    player_y -= speed; break;
    case DIR_RIGHT: player_x += speed; break;
    case DIR_LEFT:  player_x -= speed; break;
  }
}

After running player_movement your direction will be in 'direction'.
The frame of animation to render for that direction will be 'animstep / ANIMATION_RATE'.

dir4() imposes an order of precedence on your direction buttons, but that's really a pretty common thing in 4-direction schemes. If you really feel the need to direct according to the last button pressed then you can create a precedence function that reacts to key events and rewrite dir4() to prioritize that direction:


int priorityState = SDLK_DOWN;
DIRECTION priorityDir = DIR_DOWN;

void react_to_key_event() {
  if(control_event.type == SDL_KEYDOWN) {
    switch(control_event.key.keysym.sym) {
      case SDLK_DOWN:
        priorityState = SDLK_DOWN;
        priorityDir = DIR_DOWN;
        break;
      case SDLK_LEFT:
        priorityState = SDLK_LEFT;
        priorityDir = DIR_LEFT;
        break;
      case SDLK_RIGHT:
        priorityState = SDLK_RIGHT;
        priorityDir = DIR_RIGHT;
        break;
      case SDLK_UP:
        priorityState = SDLK_UP;
        priorityDir = DIR_UP;
        break;
    }
  }
}

DIRECTION dir4(Uint8* keystate) {
  if(keystate[priorityState]) {return priorityDir;}
  if(keystate[SDLK_DOWN]) {return DIR_DOWN;}
  if(keystate[SDLK_LEFT]) {return DIR_LEFT;}
  if(keystate[SDLK_RIGHT]) {return DIR_RIGHT;}
  if(keystate[SDLK_UP]) {return DIR_UP;}
  return DIR_NONE;
}

Driving input by control events is heavy on the simulation (movement must be processed for every message) and reliant on the rate at which messages are generated and etc. While the code above times the animation based on the framerate, it's in the correct format to be adjusted to a variable timestep if and when you decide to do so. The best practice is to break the system up such that all inputs (not just control input but network input and etc as well) are available, then captured at their current state and passed through a single logical frame.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement