8

私は間違いなく、新しい C++ chrono ライブラリに少し戸惑っています。

ここに更新ループがあります。次の 2 つの操作を実行します。

engine.Update()
engine.Render()

これらは長い操作であり、どれくらいの長さかを判断するのは困難です。

したがって、それらにかかった時間を測定し、いくつかの計算を行い、render を呼び出す前に update を徐々に呼び出す最善の方法を見つけます。

これを行うには、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 が非常に小さいためですが、1 秒あたり 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?

混乱させてごめんなさい。私はこの chrono ライブラリを馬鹿にしているように感じます。ほとんどのヘルプ サイト、参考資料、または直接コード自体でさえ、私がそれを何に適用しているかを読んで理解するのは非常に混乱しています。解決策やコードを探す方法についてのアドバイスは大歓迎です!

編集: Joachim は、 std::min/max がミリ秒単位で問題なく動作することを指摘しました! 変更を反映するようにコードを更新しました。

4

1 に答える 1

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 に a を渡す必要がある場合) は、次のことができます。何かのようなもの:

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

デルタを取得するには、次のようにする必要があります。

typedef std::common_type<decltype(frameTime),decltype(kMaxDeltatime)>::type common_duration;
auto mDeltaTime = std::min<common_duration>(frameTime, kMaxDeltatime); 
于 2013-04-05T17:24:28.020 に答える