如何在Box2D和SFML中设置固定的绘制速度和世界步距? [英] How to set fixed drawing speed and world steps in Box2D and SFML?

查看:115
本文介绍了如何在Box2D和SFML中设置固定的绘制速度和世界步距?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个简单的项目,Box2D从事物理学,SFML绘制。在不同机器上具有不同性能的程序的速度会有所不同。如何设置固定速度?这样一来,在一台功能强大,普通且性能较弱的计算机上,程序(对象移动)的速度是否相同?

我们需要使Box2D在不同的计算机上以相同的速度工作。
它还提供坐标,SFML在给定坐标处绘制一个正方形。如何解决此问题?

解决方案

恒定帧速率是您要寻找的。这是一个众所周知的问题。



正如您所说,不同的计算机将具有不同的处理器速度。这可能涉及具有更好硬件的计算机每秒处理您的游戏循环的次数更多。



如果您要设置固定的帧频,则例如,以60帧/秒的速度,您所要做的就是(如



我们现在要做的是使用一种称为固定时间步长的技术。我们
编写代码以确保在任何情况下,无论发生什么情况,我们始终为
提供相同的增量时间给update函数。如果您发现
听起来很困难,则与我们已经拥有的
并没有太大区别。我们只需在
的代码中进行一些记账,自上次调用 update()函数以来已经过去了多少时间。



与上面的代码类似,内含 while(timeSinceLastUpdate> TimePerFrame)



此更改的实际效果是,我们在变量 timeSinceLastUpdate 中累积了
经历了多少时间。当我们超出一帧所需的
数量时,我们减去该
帧的所需长度(即 TimePerFrame ),并更新游戏。直到
再次低于所需金额为止。这可以解决
变量增量时间的问题,因为我们保证始终运行相同数量的
帧。在您可以下载的应用程序中,通过使
TimePerFrame 常量等于<$ c,将逻辑
帧速率设置为每秒60帧$ c> sf :: seconds(1.f / 60.f)。



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?

解决方案

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).

这篇关于如何在Box2D和SFML中设置固定的绘制速度和世界步距?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆