How to set fixed drawing speed and world steps in Box2D and SFML?

岁酱吖の 提交于 2019-12-11 16:59:51

问题


There is a simple project, Box2D is engaged in physics, SFML draws. On different machines with different performance speed of the program varies. How to set a fixed speed? So that would on a powerful, average and weak computer the speed of the program (movement of objects) were the same?
We need to make Box2D work on different computers at the same speed. It also gives coordinates, and SFML draws a square at the given coordinates. How to solve this problem?


回答1:


Constant Frame Rate is what you're looking for. This is a well-known problem.

As you say, different machines will have different processor speeds. This could involve a computer with better hardware processes your game loop more times per second.

If you want to set a fixed frame rate, let say, 60 FPS, all you have to do is (as Öö Tiib pointed) limit your updates doing one update each 1/60 seconds.

This is a common implementation:

const sf::Time TimePerFrame = sf::seconds(1.f / 60.f);    // 60 FPS

void run(){
        sf::Clock clk;
        sf::Time timeSinceLastUpdate = sf::Time::Zero;
        while (_window.isOpen())
        {

            sf::Time dt = clk.restart();
            timeSinceLastUpdate += dt;
            while (timeSinceLastUpdate > TimePerFrame)
            {
                timeSinceLastUpdate -= TimePerFrame;

                processInput();
                update(TimePerFrame);
            }
            render();
        }
    }
}

This way, if a machine runs faster, you'll only update the state of your world 1 time every 1/60 seconds.


TL;DR;

When your program starts, timeSinceLastUpdate takes value 0, you check the while and get the elapsed time since clk was created (or restarted), lets say that number t1 is less than 1/60 seconds. The program add it to timeSinceLastUpdate and draw the scene, as it was created (an initial state of your game).

The second loop of your while, you get the elapsed time again (elapsed since last loop, because you restarted the clock). Lets call this time t2. Again, this number is less than 1/60 seconds, but, when you add it to timeSinceLastUpdate, both add up to a number greater than 1/60 (so timeSinceLastUpdate = t1 + t2 > TimePerFrame). This time, you will enter the second loop, and update your world as if 1/60 seconds had passed. You substract this 1/60 seconds from timeSinceLastUpdate and check again. If more than 1/60 seconds are remaining, you'll update again, until you stay up to date.

If you look careful, you only call update(TimePerFrame), so you will always update your world by chunks of 1/60 seconds.


From SFML Game Development Book. Chapter 1: Making Game Tick

Fixed time steps

The solution we have come up with so far is sufficient for many cases. But it is not a perfect solution [...] since every frame is unique, and you can't guarantee that the delta time remains the same. Consider that a frame may sometimes take three times the average delta time. This can lead to severe mistakes in the game logic, for example, when a player moves three times the distance and passes through a wall he would normally collide with. This is why physics engines expect the delta time to be fixed.

The following is a figure describing the problem we are referring to:

What we will do now is use a technique called fixed time steps. We write code that guarantees that in any circumstances, we always give the same delta time to the update function, no matter what happens. If you find that sounding difficult, there is no big difference from what we already have. We just have to do some book-keeping in our code for how much time has passed since we last called the update() function.

Code similar to the one above here, with the inner while (timeSinceLastUpdate > TimePerFrame)

The actual effect of this change is that we accumulate how much time has elapsed in a variable timeSinceLastUpdate. When we are over the required amount for one frame, we subtract the desired length of this frame (namely TimePerFrame), and update the game. We do this until we are below the required amount again. This solves the problem with variable delta times, as we are guaranteed that the same amount of frames is always run. In the application you can download, the logic frame rate will be set to 60 frames per second by having the TimePerFrame constant equal to sf::seconds(1.f / 60.f).



来源:https://stackoverflow.com/questions/54652634/how-to-set-fixed-drawing-speed-and-world-steps-in-box2d-and-sfml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!