Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Sprite animation sheet speed too fast.  (Read 1288 times)

0 Members and 1 Guest are viewing this topic.

MariosTheGreat

  • Newbie
  • *
  • Posts: 3
    • View Profile
Sprite animation sheet speed too fast.
« on: June 14, 2020, 09:24:38 pm »
Hi everyone, I am new to SFML and I'm trying to make a small game that, each piece at a time, would turn into a very small scale 2D engine. Probably very ambitious but nonetheless a curiosity of mine since my teen years.

I am in a stage where I want to have the sprite of my character animated. I got it working, despite it being very rudimentary but now the problem is that the animation goes so fast it looks ridiculous. I can find no way to tune the sprite animation rate of my character.

I am aware that there are a lot of previous questions about the same topic but for the life of me I am unable to focus on what the problem is. I am aware I need some kind of "sprite frame counter" but I have no idea on how to implement it right now.

In my player.cpp class implementation i have the following function

void Player::animation(sf::Time& dtFrame) ///SIMPLE YET WORKING :)  HOW TO REGULATE TIMING THO?
{

    ///NOTE: IT'S ALWAYS A GOOD IDEA TO USE INTEGER NUMBERS FOR EACH FRAME IN ORDER TO SATISFY EASILY THE CONDITIONS FOF SPRITE FRAME CHANGING.
   if(TextureArea.left == 0.0) //When at the left-most, which is set by default in the sprite.
   {
      moverightFrame = true;
      moveleftFrame = false;
   }

   else if( TextureArea.left == 4872 ) //When at the right-most of the sprite.
   {
        moveleftFrame = true;
        moverightFrame = false;
   }

   if(moverightFrame)
       TextureArea.left += 406;
   if(moveleftFrame)
       TextureArea.left = 0;

   Sprite.setTextureRect(TextureArea); //Take next sprite according to the previous in the sequence as determined above.


}

This works but I say said it's ridiculous. Now...as you see I have a reference that takes the clock of the game loop basically. If everything in that function is wrapped in an if-statement of the kind:

if(dtFrame.AsSeconds()>0.0167)
{
// the code above here
}

Only then the animation slows down and looks beautiful. It is basically a character walking.

First of all, why 0.0167? I deduced it from the fact that my framerate is voluntarily capped at 60fps somewhere else in the code and that there must be some relationship to 1/60Hz ~ 0.0167 seconds.

Second problem, if the pc slows down so does the framerate temporarily then the whole animation looks awful again for a few seconds.

I must be doing something highly inefficient and/or ineffective.

Sorry if there is anything confusing. Thanks in advance.

Hapax

  • Hero Member
  • *****
  • Posts: 3346
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Sprite animation sheet speed too fast.
« Reply #1 on: June 15, 2020, 09:59:13 pm »
From the look of it, I would presume that you're passing the amount of time passed for that frame to the player's animation method.

What you could do, is store an sf::Time inside the player and add to it the value of dt for that frame. Then, you could perform the texture rect "movement" (i.e. the animation frame changing) when a certain amount passes. You can then remove that certain amount of time from the stored time (you have processed this chunk so it can go). It's more rubust if you loop through that stored time with each "chunk" until there isn't enough for a full chunk.
It could be better if you think of an animation frame as an integer value first and then convert that to its texture rectangle later.

I'm thinking something like this:
// sf::Time accumulatedTime (stored in Player, initialised with sf::Time::Zero)
// unsigned int currentAnimationFrame (stored in Player, initialised with 0u)
void Player::animation(sf::Time dtFrame) // time is pretty small object so passing by value is fine here
{
    // a couple of constants that could also be stored in the player class. these would need modifying if the animation changed (number of frames or animation speed)
    const sf::Time timeChunk{ sf::seconds(0.0417f) }; // this would be 1 second divided by frames per second so 0.0417 is ~24 FPS (cinematic frame rate).
    const unsigned int numberOfAnimationFrames{ 24u }; // number of frames in your animation. this value is presumed from your code

    // process time
    accumulatedTime += dtFrame;
    while (accumulatedTime >= timeChunk)
    {
        accumulatedTime -= timeChunk;
        ++currentAnimationFrame;
    }
    currentAnimationFrame %= numberOfAnimationFrames; // keep within range by making it cycle

    // this extra "frame" part is to allow the ping-pong animation while allowing currentAnimationFrame to always ascend and cycle
    unsigned int frame{ currentAnimationFrame };
    if (frame > 12u)
        frame = 24u - frame;

    // set texture rect from frame
    TextureArea.left = 406u * frame;
    Sprite.setTextureRect(TextureArea);
}

Your code seems to use "ping-pong" animation so I've included this as well.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

MariosTheGreat

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Sprite animation sheet speed too fast.
« Reply #2 on: June 16, 2020, 03:37:07 pm »
Hi thank you very much for your answer. I had a similar idea yesterday evening and tested it. Your reply also confirms my initial idea but it is also much better developed. So I am going to study your code and try to incorporate it in mine.

Thank you very much for your I really appreciate it.