0
\$\begingroup\$

Similar to this question https://stackoverflow.com/questions/33904998/sfml-extremly-slow-irregular-framerate, I have created a small program to experiment with SFML

I have a very simple SFML test application on ubuntu 20.04 using SFML 2.5.1. There are three circles. One under user control and one bouncing left to right.

Problems:

  • The one moving left to right is not very fast.
  • Even so the one under user control cannot keep up with it.
  • I am using a delta of 1 (pixel per frame?). If I increase this motion is jumpy rather than smooth.

Put simply it feels clunky. So I am assuming I've made a noob error of some kind. However, this seems to be the same basic SFML game loop commonly used. How can I make this fast and slick feeling instead?

#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
    const float FPS = 120.0f; //The desired FPS. (The number of updates each second).
    bool redraw = true;      //Do I redraw everything on the screen?
    window.setFramerateLimit(FPS);
    sf::CircleShape shape2(100.f);
    sf::CircleShape shape(10.f);
    sf::Clock clock;
    shape2.setFillColor(sf::Color::Green);
    shape.setFillColor(sf::Color::Red);

    sf::CircleShape alien(10.f);
    alien.setFillColor(sf::Color::Yellow);
    auto alienSpeed = 1.f;
   
    while (window.isOpen())
    {
        sf::Event event;
        float xDelta = 0;
        float yDelta = 0;
        bool moved = false;
        if (window.pollEvent(event))
        {
           if (event.type == sf::Event::Closed)
           {
              window.close();
           }
           if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            {
               xDelta -= 1.f;
               moved = true;
            }
            else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            {
               xDelta += 1.f;
               moved = true;
            }
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            {
               yDelta -= 1.f;
               moved = true;
            }
            else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            {
               yDelta += 1.f;
               moved = true;
            }
        }

        if (xDelta !=0 || yDelta != 0)
        {
           shape.move(xDelta,yDelta);
        }

        alien.move(alienSpeed, 0.f);
        if (alien.getPosition().x >= 190)
        {
           alienSpeed = -1.f;
        }
        else if (alien.getPosition().x <= 0)
        {
           alienSpeed = 1.f;
        }

        if(redraw)
        {
           window.clear();
           window.draw(shape2);
           window.draw(shape);
           window.draw(alien);
           window.display();
        }
    }

    return 0;
}

Note: cross posted to https://en.sfml-dev.org/forums/index.php?topic=27617.0

\$\endgroup\$
1
  • 1
    \$\begingroup\$ It looks like your game loop is missing the notion of a time step. Your code assumes that exactly one pixel worth of time has passed in each iteration. But if you time the loop, I bet that's not the case. You probably have some iterations that happen closer back-to-back than others. At higher velocities, that can create an effect called "judder" — where our eye, assuming the object is moving at a constant-ish velocity, expects the object to be in one place by now, but it actually ends up a few pixels ahead or behind because of this time variation, making it look like it's jumping or vibrating. \$\endgroup\$
    – DMGregory
    Sep 19, 2020 at 13:49

1 Answer 1

1
\$\begingroup\$

Answered in the SFML forum by eXpl0it3r:

You should not be mixing events and real-time inputs, see the dedicated tutorials.

Events: https://www.sfml-dev.org/tutorials/2.5/window-events.php Real-time input: https://www.sfml-dev.org/tutorials/2.5/window-inputs.php

It is (as I thought) a noob error. sf::Keyboard::isKeyPressed() is not an event and does not belong inside the event processing loop. With isKeyPressed() outside that loop its much better. It should be:

    if (window.pollEvent(event))
    {
       if (event.type == sf::Event::Closed)
       {
          window.close();
       }
    }

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
    {
           xDelta -= 1;
    }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .