I am coding a simple game with roguelike in C ++ using the SDL library, and I am having problems moving my character on the screen. Every time I need to render a frame, I update the position of the sprite using the update () function, which does nothing if the player stands still. To issue a move command and thus start the animation, I use the step () function, which is called only once for each movement of the player from one tile to another. Having received the “up” command, the game behaves perfectly, and the character smoothly moves in one second to a new position. However, when the “down” command is given, it moves about half the speed, and, obviously, after one second it instantly “teleports” to the final position with a sudden flicker. The code for the movement is basically identical, but for the fact that in one case the delta movement is summed with the y-position, in the other case it is subtracted. Perhaps the fact that the position is an integer and the delta is double causes problems? Does sum and similarity do things differently (maybe a different rounding)? Here is the relevant code (sorry for the length):
void Player::step(Player::Direction dir) { if(m_status != STANDING) // no animation while standing return; switch(dir) { case UP: if(m_currMap->tileAt(m_xPos, m_yPos - m_currMap->tileHeight())->m_type == Tile::FLOOR) { // if next tile is not a wall, set up animation m_status = WALKING_UP; m_yDelta = m_currMap->tileHeight(); // sprite have to move by a tile m_yVel = m_currMap->tileHeight() / 1000.0f; // in one second m_yNext = m_yPos - m_currMap->tileHeight(); // store final destination } break; case DOWN: if(m_currMap->tileAt(m_xPos, m_yPos + m_currMap->tileHeight())->m_type == Tile::FLOOR) { m_status = WALKING_DOWN; m_yDelta = m_currMap->tileHeight(); m_yVel = m_currMap->tileHeight() / 1000.0f; m_yNext = m_yPos + m_currMap->tileHeight(); } break; //... default: break; } m_animTimer = SDL_GetTicks(); } void Player::update() { m_animTimer = SDL_GetTicks() - m_animTimer; // get the ms passed since last update switch(m_status) { case WALKING_UP: m_yPos -= m_yVel * m_animTimer; // update position m_yDelta -= m_yVel * m_animTimer; // update the remaining space break; case WALKING_DOWN: m_yPos += m_yVel * m_animTimer; m_yDelta -= m_yVel * m_animTimer; break; //... default: break; } if(m_xDelta <= 0 && m_yDelta <= 0) // if i'm done moving { m_xPos = m_xNext; // adjust position m_yPos = m_yNext; m_status = STANDING; // and stop } else m_animTimer = SDL_GetTicks(); // else update timer }
EDIT: I deleted some variables and left only the elapsed time, speed and end position. Now it moves without flickering, but moving down and to the right is noticeably slower than the top and left. Still wondering why ...
EDIT 2: Well, I understood why this is happening. As I suggested in the first place, there is a different rounding from double to integer when it comes to sum and subtraction. If I do the throw as follows:
m_xPos += (int)(m_xVel * m_animTimer);
the animation speed is the same and the problem is resolved.
source share