我对新的C ++ chrono库肯定有点失落。
这里我有一个更新循环。它运行两个操作:
engine.Update()
engine.Render()
这些操作很长,而且很难判断它们有多长。
因此,我们测量他们花了多长时间,然后进行一些计算并找出在调用渲染之前逐渐调用更新的最佳方法。
要做到这一点,我正在使用C ++ 11的Chrono功能。我选择它是因为它听起来很划算:更准确,更依赖于平台。我发现我现在遇到的问题比现在更多。
以下是我的代码,以及我的主要问题。非常需要任何有关问题或正确操作方法的帮助!
我在相关行旁边的评论中标记了我的问题,我将在下面重复这些问题。
标题文件:
class MyClass
{
private:
typedef std::chrono::high_resolution_clock Clock;
Clock::time_point mLastEndTime;
milliseconds mDeltaTime;
}
简化的更新循环
// 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();
}
主要问题是: 我的mDeltaTime总是很小。它基本上停留在几乎无限的循环中。这是因为kMaxDeltatime非常小,但是如果我的目标是每秒60帧,那么我不计算正确的毫秒数吗?
以下是上面列出的所有问题:
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?
我很抱歉这些混乱的人。我觉得这个计时库是个白痴。大多数帮助网站,或参考资料,甚至直接代码本身都非常令人困惑,无法阅读和理解我正在应用它。我非常欢迎指向我应该如何搜索解决方案或代码!
编辑: Joachim指出std :: min / max可以正常工作几毫秒!更新了代码以反映变化。
答案 0 :(得分:20)
使用std::chrono
时,您应尽可能避免投射持续时间或将持续时间转换为原始整数值。相反,你应该坚持使用自然持续时间,并利用持续时间类型提供的类型安全性。
以下是一系列具体建议。对于每个推荐,我引用原始代码的行,然后显示我将如何重写这些行。
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!
没有理由使用手动转换常量进行此类计算。相反,你可以这样做:
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?
您可以将值保留为其原生类型:
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?
改为使用:
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?
最好编写始终使用chrono::duration
类型的代码,而不是使用泛型整数类型,但如果你真的需要获得泛型整数类型(例如,如果你必须通过long
到第三方API)然后您可以执行以下操作:
auto mDeltaTime = ... // some duration type
long milliseconds = std::chrono::duration_cast<std::duration<long,std::milli>>(mDeltaTime).count();
third_party_api(milliseconds);
或者:
auto milliseconds = mDeltaTime/milliseconds(1);
要获得delta,您应该执行以下操作:
typedef std::common_type<decltype(frameTime),decltype(kMaxDeltatime)>::type common_duration;
auto mDeltaTime = std::min<common_duration>(frameTime, kMaxDeltatime);