使用C ++ Chrono处理更新循环? [英] Handling an update loop using C++ Chrono?

查看:125
本文介绍了使用C ++ Chrono处理更新循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我有一个更新循环。它运行两个操作:

  engine.Update()
engine.Render()

这些都是很长的操作,很难判断它们有多长。



因此,我们测量它们花了多长时间,然后做一些计算,并计算在我们调用render之前逐渐调用update的最佳方法。



为此, m使用C ++ 11的Chrono功能。我选择它,因为它听起来像一个很好的协议:更准确,更多的平台依赖。我发现我现在遇到比现在更多的问题。



下面是我的代码,以及我的主要问题。任何帮助,无论是问题,还是一个正确的方式来做我的操作,是非常需要的!



我在问题的直接旁边的评论中标记我的问题,



头文件:

  class MyClass 
{
private:
typedef std :: chrono :: high_resolution_clock时钟;
Clock :: time_point mLastEndTime;
milliseconds mDeltaTime;
}

简化的更新循环

  //上次循环的时间
毫秒frameTime;
//最高的,我们会让那个时间去。 60 fps = 1/60,以毫秒为单位,* 1000
const毫秒kMaxDeltatime((int)((1.0f / 60.0f)* 1000.0f)); //这很难说,但这似乎出来了一些微小的数,而不是我的预期!
while(true)
{
//最后一次更新需要多长时间?
frameTime = duration_cast< milliseconds>(Clock :: now() - mLastEndTime); //这是获取增量时间的最佳方式,有持续时间投放吗?
//标记最后更新时间
mLastEndTime = Clock :: now();

//不要使用frameTime更新所​​有内容,请将其保持在最大fps以下。
while(frameTime.count()> 0)//这是测量大于0毫秒的最好方法吗?
{
//确定最小时间。我们的frametime,或最大delta时间?
mDeltaTime = min(frameTime,kMaxDeltatime);

//更新我们的引擎。
engine-> Update((long)mDeltaTime.count()); //从这里,它很容易处理longs中的代码。这是最好的方式推一个长的我的代码?

//从总更新时间中减去增量时间
frameTime - = mDeltaTime;
}
engine-> Render();
}

主要问题是:
我的mDeltaTime总是很小。它基本上停留在几乎无限循环中。这是因为kMaxDeltatime超小,但如果我的目标是60帧每秒,我没有计算正确的毫秒吗?



这里是所有的问题列出

  const milliseconds kMaxDeltatime((int)((1.0f / 60.0f)* 1000.0f)); //这很难说,但这似乎出来了一些微小的数,而不是我的预期! 

frameTime = duration_cast< milliseconds>(Clock :: now() - mLastEndTime); //这是获取增量时间的最佳方式,有持续时间投放吗?

while(frameTime.count()> 0)//这是测量大于0毫秒的最好方法吗?

engine-> Update((long)mDeltaTime.count()); //从这里,它很容易处理longs中的代码。这是最好的方式推一个长的我的代码?

对不起,混乱的家伙。我觉得像一个白痴与这个计时器图书馆。大多数帮助网站,或参考资料,甚至直接代码本身是非常混乱阅读和理解我应用它。指针到我应该如何寻找解决方案或代码是非常欢迎!



编辑:
Joachim指出std :: min / max工作很好为毫秒! cd>使用 std :: chrono 更新代码以反映更改

解决方案

您应该尽可能避免投射持续时间或将持续时间转换为原始整数值。相反,你应该坚持自然的持续时间,并利用持续时间类型提供的类型安全。



以下是一系列具体的建议。对于每个建议,我将引用原始代码的行,然后显示我将如何重写这些行。







  const milliseconds kMaxDeltatime((int)((1.0f / 60.0f)* 1000.0f)); //这很难说,但这似乎出来了一些微小的数,而不是我的预期! 


没有理由使用手动转换常数进行这种计算。您可以这样做:

  typedef duration< long,std :: ratio< 1,60>六分之一
constexpr auto kMaxDeltatime = sixtieths_of_a_sec {1};







  frameTime = duration_cast< milliseconds>(Clock :: now() -  mLastEndTime); //这是获取增量时间的最好方法,有持续时间投射吗? 


您可以将值保留为其原生类型:

  auto newEndTime = Clock :: now(); 
auto frameTime = newEndTime - mLastEndTime;
mLastEndTime = newEndTime;







  while(frameTime.count()> 0)//这是测量大于0毫秒的最好方法吗? 


而是使用:

  while(frameTime> milliseconds(0))







  engine-> Update((long)mDeltaTime.count()); //从这里,它很容易处理longs中的代码。这是最好的方式推一个长的我的代码? 


最好使用 chrono :: duration 类型,而不是使用通用的整型类型,但如果你真的需要一个通用的整型类型(例如,如果你必须传递 long 到第三方API),那么您可以执行以下操作:

  auto mDeltaTime = 。//一些持续时间类型

long milliseconds = std :: chrono :: duration_cast< std :: duration< long,std :: milli>(mDeltaTime).count();
third_party_api(milliseconds);

要获得增量,您应该执行以下操作:

  typedef std :: common_type< decltype(frameTime),decltype(kMaxDeltatime)> :: type common_duration; 
auto mDeltaTime = std :: min< common_duration>(frameTime,kMaxDeltatime);


I'm definitely a bit lost with the new C++ chrono library.

Here I have an update loop. It runs two operations:

engine.Update()
engine.Render()

These are long operations, and it's hard to tell how long they are.

Thus, we measure how long they took, then do some calculations and figure the best way to gradually call update before we call render.

To do this, i'm using C++11's Chrono functionality. I chose it because it sounded like a good deal: More accurate, More platform dependent. I'm finding i'm hitting more problems than now now though.

Following is my code, as well as my primary problem. Any help on either the problem, or a proper way to do my operations, is greatly needed!

I marked my questions in comments directly next to the lines in question, which i'll re-iterate below.

The header file:

class MyClass
{
private:
    typedef std::chrono::high_resolution_clock Clock;
    Clock::time_point mLastEndTime;
    milliseconds mDeltaTime;
}

The simplified update loop

// time it took last loop
milliseconds frameTime;
// The highest we'll let that time go. 60 fps = 1/60, and in milliseconds, * 1000
const milliseconds kMaxDeltatime((int)((1.0f / 60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected!
while (true)
{
    // How long did the last update take?
    frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast?
    // Mark the last update time
    mLastEndTime = Clock::now();

    // Don't update everything with the frameTime, keep it below our maximum fps.
    while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds?
    {
        // Determine the minimum time. Our frametime, or the max delta time?
        mDeltaTime = min(frameTime, kMaxDeltatime);

        // Update our engine.
        engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code?

        // Subtract the delta time out of the total update time 
        frameTime -= mDeltaTime;
    }
    engine->Render();
}

The main question is: My mDeltaTime always comes out tiny. It's basically stuck in an almost-infinite loop. This is because the kMaxDeltatime is super small, but if i'm targeting 60 Frames per Second, didn't I calculate the correct milliseconds?

Here are all the questions listed from above:

const milliseconds kMaxDeltatime((int)((1.0f / 60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected!

frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast?

while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds?

engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code?

I'm sorry for the confusion guys. I feel like an idiot with this chrono library. Most of the help sites, or reference material, or even the direct code itself is very confusing to read and understand to what i'm applying it to. Pointers into how I should be searching for solutions or code are very much welcomed!

EDIT: Joachim pointed out that std::min/max works just fine for milliseconds! Updated code to reflect change.

解决方案

When using std::chrono you should avoid, as much as possible, casting durations or converting durations to raw integral values. Instead you should stick with the natural durations and take advantage of the type safety that duration types provide.

Below is a series of specific recommendations. For each recommendation I'll quote lines of your original code and then show how I would re-write those lines.


const milliseconds kMaxDeltatime((int)((1.0f / 60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected!

There's no reason to do this sort of computation with manual conversion constants. Instead you can do:

typedef duration<long,std::ratio<1,60>> sixtieths_of_a_sec;
constexpr auto kMaxDeltatime = sixtieths_of_a_sec{1};


frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast?

You can just keep the value in its native type:

auto newEndTime = Clock::now();
auto frameTime = newEndTime - mLastEndTime;
mLastEndTime = newEndTime;


while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds?

Instead use:

while (frameTime > milliseconds(0))


engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code?

It's best to write code that uses chrono::duration types throughout, rather than to use generic integral types at all, but if you really need to get a generic integral type (for example if you must pass a long to a third-party API) then you can do something like:

auto mDeltaTime = ... // some duration type

long milliseconds = std::chrono::duration_cast<std::duration<long,std::milli>>(mDeltaTime).count();
third_party_api(milliseconds);

And to get the delta you should do something like:

typedef std::common_type<decltype(frameTime),decltype(kMaxDeltatime)>::type common_duration;
auto mDeltaTime = std::min<common_duration>(frameTime, kMaxDeltatime); 

这篇关于使用C ++ Chrono处理更新循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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