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

Author Topic: Completely Eliminating Jittery Movement  (Read 9429 times)

0 Members and 1 Guest are viewing this topic.

fatum

  • Newbie
  • *
  • Posts: 47
    • MSN Messenger - bowsers7@hotmail.com
    • AOL Instant Messenger - therealblah569
    • View Profile
    • http://boards.psynetfm.com
Completely Eliminating Jittery Movement
« on: October 21, 2013, 09:16:22 pm »
First, before getting started, I'd like to define what I mean by jittery movement — every 500 ticks or so, the sprite being moved might jerk forward a little bit, and then snap back in place, thus appearing to be jittery/stuttering while moving.

The stuttering is a lot more apparent if I force hard vertical synchronization or specify a capped frame rate limit using the SFML API, which I assume is because I've already implemented a fixed timestep and interpolation that might not work well with these limits.

The stuttering is hardly noticeable for me, but it's a lot more apparent for my friends with lower-end hardware, so I think I'm just doing things inefficiently.  Currently, I've turned off everything except for x movement for the player class to make the scope of the problem easier to manage. 

Game Loop:
void Application::initialize()
{
        videoMode.width = 1067;
        videoMode.height = 600;
        videoMode.bitsPerPixel = 32;
       
        dt = 1.0f / 60.0f;
        timeNow = gameClock.getElapsedTime().asSeconds();
        timeFrame = 0.0f;
        timeActual = 0.0f;
        accumulator = 0.0f;
       
        enableVSync = false;
        doForceFPS = false;
        forceFPS = 60;
}

int Application::run(int argc, char **argv)
{      
        ...

        pushWorld(new TownlevelWorld());
       
        while (rwin.isOpen())
        {              
                sf::Event event;
                while (rwin.pollEvent(event))
                {
                        cont_worlds.top()->input(event);
                        ...
                }

                timeNow = gameClock.getElapsedTime().asSeconds();
                timeFrame = timeNow - timeActual;
               
                if (timeFrame > 0.25f)
                        timeFrame = 0.25f;
               
                timeActual = timeNow;
                accumulator += timeFrame;
               
                while (accumulator >= dt)
                {
                        cont_worlds.top()->update(dt);
                        accumulator -= dt;
                }
               
                const float interpolation = accumulator / dt;

                rwin.clear();
                cont_worlds.top()->draw(rwin, interpolation);
                rwin.display();
        }
        release();
        return 0;
}

Player.cpp:
void Player::draw(sf::RenderWindow &rwin, float interp)
{
        rwin.draw(self);

        sf::Vector2f posInterp = pos;
       
        if (pos.x != lastPos.x)
                posInterp.x += interp;
        if (pos.y != lastPos.y)
                posInterp.y += interp;
       
        self.setPosition(posInterp.x, posInterp.y);
        lastPos = pos; 
}

void Player::update(float dt)
{      
        if (right == true && left == false)
        {
                xs += speed;
        }
       
        if (right == false && left == true)
        {
                xs -= speed;
        }

        if (!sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
                right = false;
                left = false;

        }
       
        pos.x += clamp(xs, -6, 6);
        xs /= fric;
}
 

I'd appreciate any help to see if I'm doing things inefficiently, or what else might be causing the occasional stuttering.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Completely Eliminating Jittery Movement
« Reply #1 on: October 21, 2013, 09:48:13 pm »
Unfortunately that code isn't complete so all I can really do is guess and say you should try doing things differently in your update() function and see what happens.  As just one example, we can't see where left/right get set.

Plus, for semi-subjective issues like this, it's extremely helpful (even more so than usual) if we can compile your code and actually see the problem.

fatum

  • Newbie
  • *
  • Posts: 47
    • MSN Messenger - bowsers7@hotmail.com
    • AOL Instant Messenger - therealblah569
    • View Profile
    • http://boards.psynetfm.com
Re: Completely Eliminating Jittery Movement
« Reply #2 on: October 22, 2013, 12:24:55 am »
Unfortunately that code isn't complete so all I can really do is guess and say you should try doing things differently in your update() function and see what happens.  As just one example, we can't see where left/right get set.

Plus, for semi-subjective issues like this, it's extremely helpful (even more so than usual) if we can compile your code and actually see the problem.

Here's a very minimal example on a public github repository.  I stripped away all the unnecessary things like animation classes and everything else to re-create the issue with the least amount of code.

It might be hard to notice at first without using any command line arguments, you might even need to look extra hard if you're running higher-end hardware.  I'm able to reproduce it if I move all the way to the right edge of the screen and all the way back to the left edge of the screen over and over again.

It's a lot more noticeable as soon as you use the "--force-fps ##" and the "--enable-vsync" command line arguments when running the example.

Thanks for any help with optimizing or helping me alter things to become more efficient!

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Completely Eliminating Jittery Movement
« Reply #3 on: October 22, 2013, 02:04:12 am »
If you want to follow that infamous article, you should really follow it all the way and more importantly understand what is said there. It was even explicitly mentioned that you would encounter stuttering if you didn't perform proper interpolation. I changed the last 2 methods of your player code to:
void Player::draw(sf::RenderWindow &rwin, float interp)
{
        // Perform linear interpolation between last state and current state.
        sf::Vector2f posInterp = pos * interp + lastPos * ( 1.f - interp );

        self.setPosition(posInterp);
       
        rwin.draw(self);
}

void Player::update(float dt)
{
        // Save state before the last update before drawing.
        lastPos = pos;

        if (right == true && left == false)
        {
                xs += speed;
        }

        if (right == false && left == true)
        {
                xs -= speed;
        }

        if (!sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
                right = false;
                left = false;
        }

        pos.x += clamp(xs, -6, 6);
        xs /= fric;

        // Get rid of floating point instability.
        if( std::abs( xs ) < 0.4f ) {
                xs = 0.f;
        }
}
and the visible artefacts are gone for me. The difference between the original and my code are marked by comments. You need to perform proper linear interpolation between both states, not just an addition to the current one. If you just added the difference that was missing, of course the position would bounce back and forth depending on how much time is left in the update loop, and that depends on the synchronization between the FPS and your fixed delta leading to what you described on different systems.

To get rid of the "vibration" artefacts when slowing down, all you need to do is snap the movement down to 0 once it is under whatever threshold you choose. If you don't do that and continue to divide a floating point number, it will keep getting smaller and smaller and thus keep losing precision as well leading to those instabilities at the start. At some point it will be so small that even drawing that difference won't lead to any change which is why you only see it at the start of the "slowing down" phase.

You really have to consider whether having such a complicated simulation is worth the effort. This is really only necessary when you need deterministic reproducibility which is not the case in most games. Unless the simpler delta update variant leads to significant problems, I wouldn't overdo it and focus on more productive issues. And if you think that with this method, a simulation will be deterministic no matter what, think again. As a hardware developer, I have experience dealing with floating point hardware, and trust me when I say that so many tricks are employed you should be happy that 1 + 1 = 2 although technically that is a lie as well. In the end, all I can say is that unless you are willing to go the whole nine yards, you shouldn't waste your time on these micro-optimizations.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: Completely Eliminating Jittery Movement
« Reply #4 on: October 22, 2013, 02:39:39 pm »
...
Not using real time events in movement is the reason its so Jiggering.
I will put a quote from tutorial
Quote from: Tutorial
Sometimes, people try to use the KeyPressed event to implement smooth movement. Doing so will not produce smooth movements, because when you hold a key you only get a few events (remember, the repeat delay). Smooth movements can only be achieved by using real-time keyboard input with sf::Keyboard

To fix the movement make something like
Code: [Select]
bool isKeyWPressed = false;
//Event loop
case sf::Event::KeyPressed:
switch(event.key.code)
{
case sf::Keyboard::W:
isKeyWPressed = true;
break;
}
break;
case sf::Event::KeyReleased:
switch(event.key.code)
{
case sf::Keyboard::W:
isKewWPressed = false;
break;
}
break;
Do note there are many things to take in account like, losing focus on screen then releasing the W, then the window gains focus and it never got that W was released... do read upon it i suggest.
« Last Edit: October 22, 2013, 02:45:19 pm by BaneTrapper »
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Completely Eliminating Jittery Movement
« Reply #5 on: October 22, 2013, 06:43:18 pm »
...
???

If you look at the code fatum provided on GitHub you would see all the things you claim aren't done were already done. Even the code example you posted can be found exactly 1:1. I really don't get how you can assume something is done wrong in the code without actually looking at it...
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: Completely Eliminating Jittery Movement
« Reply #6 on: October 22, 2013, 09:21:05 pm »
I did not notice that, did not read everything through in depth.
Saw in first post not using real time events so  :-[.
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

fatum

  • Newbie
  • *
  • Posts: 47
    • MSN Messenger - bowsers7@hotmail.com
    • AOL Instant Messenger - therealblah569
    • View Profile
    • http://boards.psynetfm.com
Re: Completely Eliminating Jittery Movement
« Reply #7 on: October 22, 2013, 09:37:15 pm »
If you want to follow that infamous article, you should really follow it all the way and more importantly understand what is said there. It was even explicitly mentioned that you would encounter stuttering if you didn't perform proper interpolation. I changed the last 2 methods of your player code to:

Thanks for your massive help and pointing me into the right direction!  It's working a lot better now, starting to add all of the other big elements back.  Did you happen to notice any other inefficiencies with my game loop?  I'm not sure if it's a bad idea to keep passing off an instance to my sf::RenderWindow for every ::draw function either. 

I agree, it's a bit silly for all of these micro-optimizations, but occasionally the stuttering is definitely noticeable whenever there isn't much going on, which is annoying and shouldn't be happening at all.

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Completely Eliminating Jittery Movement
« Reply #8 on: October 22, 2013, 09:41:48 pm »
I'm not sure if it's a bad idea to keep passing off an instance to my sf::RenderWindow for every ::draw function either. 

When your pass by reference (which is required since you can't copy a RenderWindow) you are just passing a pointer to your window. There is nothing inefficient about this at all. Maybe do a bit of reading on how references/pointers work  ;)
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Completely Eliminating Jittery Movement
« Reply #9 on: October 22, 2013, 09:53:36 pm »
Stuttering isn't a result of any form of "time step method", it is the cause of something else in your code.

Just forget about using a fixed time step and focus on what matters: getting your game into a playable, fun state. That article is obviously geared to people who have passed that stage and are trying to polish their game, if what is mentioned in that article is even required, as I already explained above. Out of all the projects presented here on the SFML forum I haven't seen one that can realistically benefit from having a fixed time step, which is why I hate it when people recommend that article to beginners who are obviously struggling with other things and should better spend their time on those instead of this.

Do not recommend that article to beginners, please. Whoever understands why they would benefit from something like that will find it themselves when the time comes.

Just throw out that stuff, use a simple delta update and enjoy finishing the rest of your game. There are much more important issues... seriously...

As for optimizations, I'd recommend just learning to profile your code to speed up the things that need to be done and see what is unnecessary so you can get rid of them. The only way to make code faster, is to gather experience and get a feeling for writing efficient code. I'm helping you by not helping you, if that makes any sense.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

fatum

  • Newbie
  • *
  • Posts: 47
    • MSN Messenger - bowsers7@hotmail.com
    • AOL Instant Messenger - therealblah569
    • View Profile
    • http://boards.psynetfm.com
Re: Completely Eliminating Jittery Movement
« Reply #10 on: October 22, 2013, 11:22:40 pm »
Stuttering isn't a result of any form of "time step method", it is the cause of something else in your code.

Just forget about using a fixed time step and focus on what matters: getting your game into a playable, fun state. That article is obviously geared to people who have passed that stage and are trying to polish their game, if what is mentioned in that article is even required, as I already explained above. Out of all the projects presented here on the SFML forum I haven't seen one that can realistically benefit from having a fixed time step, which is why I hate it when people recommend that article to beginners who are obviously struggling with other things and should better spend their time on those instead of this.

Do not recommend that article to beginners, please. Whoever understands why they would benefit from something like that will find it themselves when the time comes.

Just throw out that stuff, use a simple delta update and enjoy finishing the rest of your game. There are much more important issues... seriously...

As for optimizations, I'd recommend just learning to profile your code to speed up the things that need to be done and see what is unnecessary so you can get rid of them. The only way to make code faster, is to gather experience and get a feeling for writing efficient code. I'm helping you by not helping you, if that makes any sense.

I've actually been working on this game for the past 3 years or so, and it's gone through a lot of drastic changes throughout the course of that time.  I've found that a fixed time step provides the smoothest and most consistent physics simulations for my game, unlike with using delta time where I have difficulty making the physics and movement feel the same across multiple computers and hardware configurations.

I've been profiling my game every day, and I've noticed that most of the slowness & sluggish movement happens during the relevant ::draw functions.  It appears to be very random as well, with no correlation between the current running time.  It can very from 0.25 μs all the way to 120 μs as well, which should be marginally micro (hue hue) but that's the only location I can pin for the occasional sluggish movement and/or rendering.

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Completely Eliminating Jittery Movement
« Reply #11 on: October 22, 2013, 11:47:03 pm »
You need to define what this "slowness" and "sluggish movement" are. Is it simply a frame rate drop? Or is it something that is related to the physics updates in the game? If the frame rate doesn't drop, then profiling won't help you. In that case it is something to do with the physics computations involved, and there is nobody better to find the source of the problem than the one who wrote it...
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10823
    • View Profile
    • development blog
    • Email
Re: Completely Eliminating Jittery Movement
« Reply #12 on: October 23, 2013, 08:56:28 am »
This starts to sound rather similar to a few topics we had in the past. In other cases the source of the "lags" were found in some OpenGL glGetSomething functions iirc, you might want to search through the forum a bit.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/