7

私は現在、大学でコンピューター ゲーム プログラミングを行っており、C++ で物理エンジンを作成しています。

GetTickCount() メソッドを使用してタイムステップを導入するように求められましたが、不正確ではありますが、これはタイム ステップに入る現在の深度に適しているためです。

私の問題は、タイムステップ ベースの動きを導入したことです。更新関数の 2 つの異なるオーバーライドを介して画面に描画されているオブジェクトが機能していないようです。

コードにブレークポイントを追加すると、mElapsedTime に値が渡されないように見えて困惑します。

この投稿が冗長すぎるか、トピックから外れている場合は申し訳ありません。できるだけ多くのコンテキストを提供しようとしましたが、これは私の最初の投稿です。

(frameStartTime パラメータは、フレームが更新されて描画される前にティック カウントを取るだけです)

編集: float 型の mElapsed time は、パーティクル クラスの更新で乗算を容易にするため (例: pos.x = velocity.x * timeStep)、これが unsigned long から float へのキャストの理由です。それはまだ冗長ですか? ?

void Simulation::gameLoopDelay(DWORD frameStartTime)
{
    DWORD presetFrameInterval = 16;
    DWORD frameProcessingTime = GetTickCount() - frameStartTime;

    if (frameProcessingTime < presetFrameInterval)
    {
        Sleep(presetFrameInterval - frameProcessingTime);
    }

    mElapsedTime = (float)frameProcessingTime / 1000.0f;
}
4

2 に答える 2

1

基本的に、コードを次のように変更する必要があると思います。

void Simulation::gameLoopDelay(DWORD frameStartTime)
{
    DWORD presetFrameInterval = 16;
    DWORD frameProcessingTime = GetTickCount() - frameStartTime;

    if (frameProcessingTime < presetFrameInterval)
    {
        Sleep(presetFrameInterval - frameProcessingTime);
    }

    frameProcessingTime = GetTickCount() - frameStartTime;

    mElapsedTime = (float)frameProcessingTime / 1000.0f;
}

これはSleepおそらくスレッド全体をロックアウトしているため、これを行うための最も推奨される方法ではありません。ほんの少しの時間でフレームを実行する方がおそらく良いでしょうが、これでコードが修正されると思います。

于 2013-03-19T20:11:21.293 に答える
1

(十分な情報を提供しなかったため)絶対にわかりませんが、最初に目にする問題は、にmElapsedTime = (float)frameProcessingTime / 1000.0f;関係なく提供していることですSleep(...)。言い換えれば、あなたは睡眠を考慮に入れるのを忘れていました。これを行うには、をGetTickCount()呼び出した後に再フェッチする必要がありますSleep(...)。しかし、それでも、コードは定型化されすぎてエラーが発生しやすくなります。

簡単なタスクを実行する、小さく、柔軟で、再利用可能なクラスを作成して、問題への取り組みを開始します。

class Stopwatch {
public:
  Stopwatch(): _start(0), _elapsed(0), _running(false) {}

  void
  start() {
    if (_running)
      return;

    _running = true;
    _start   = GetTickCount();
  }

  void
  stop() {
    if (!_running)
      return;

    _elapsed += GetTickCount() - _start;
    _running  = false;
  }

  void
  reset() {
    _running = false;
    _elapsed = 0;
  }

  void
  restart() {
    _running = true;
    _elapsed = 0;
    _start   = GetTickCount();
  }

  bool
  isRunning() const {
    return _running;
  }

  DWORD
  elapsed() const {
    return _running ? _elapsed + (GetTickCount() - _start) : _elapsed);
  }

  bool
  hasExpired(DWORD interval) const {
    return elapsed() > interval;
  }

private:
  DWORD _start;
  DWORD _elapsed;
  bool  _running;
};

このクラスをニーズに合わせて利用する方法は簡単です。

第二に、なぜあなたがを使用するのか私は本当にわかりませんSleep。フレーム遅延の例を最後に見たのは、約5年前、おもちゃのゲームを書くためのくだらないチュートリアルでした。このようなものは古いゲームでは本当に人気がありましたが、現代のゲームでは意味がありません。もちろん、これがあなたの割り当ての要件である場合は、お詫び申し上げますが、コメントは引き続き適用されます。

最後に、リアルタイムの視覚化に関する私自身の経験から、追加のアドバイスを提供したいと思います。Windows API(またはLinux API、関係ありません)プログラマーの間で、または他の人気のあるがらくたなどの生の機能を使用して時間依存コードを記述しないGetTickCountでください。これも、おもちゃのゲームを作成するための時代遅れのチュートリアルのような匂いがします。

それでは何を使うべきか、あなたは尋ねますか?さて、最近では、Boostなどの適切に設計された信頼性の高いクロスプラットフォームライブラリが存在するため、幸運です。あなたはおそらくそれに精通しているはずです、しかしあなたがそうでないなら-あなたは間違いなくそうするべきです。あなたの特定の問題のために、適切に時間とともに動作するように注意深く設計されたモジュールBoost.Chronoがあります。私はリアルタイムレンダリングを含むいくつかのプロジェクトでそれを使用しました、そして私はそれが非常に頑強で学ぶ価値があることを認めなければなりません。

もう1つのライブラリ(Boost.Units)は、安定した正確な物理エンジンを作成するために必須です。このライブラリは、さまざまな単位系モデル(SIやCGSなど)の単位(力、質量、速度、加速度など)と数量のタイプセーフなサポートを提供します。テンプレートメタプログラミングに基づいているため、実行時のオーバーヘッドは発生しません。

繰り返しになりますが、あなたの割り当てではおそらくそのようなことは許可されていないことを理解しています。しかし、私がここで言及したことはすべて、将来あなたにとって価値があると信じています。ちなみに、これは、実際の問題を解決するために大学の課題が提供するよりもどれだけ多くのことを知っておくべきかを示す良い例です。

特に問題についてさらにサポートが必要な場合は、さらに情報が必要です。たとえば、ゲームループのコード全体を表示することから始めます。

于 2013-03-19T20:12:12.807 に答える