2009-05-28 3 views
4

Visual C++ 2008 ExpressとOgre3D SDKを使用してゲームをプログラミングしています。ゲームプレイロジックへの非同期画面更新、C++

私のコアゲームプレイロジックは100回/秒で動作するように設計されています。簡単にするために、私はそれを 'gamelogic()'と呼ばれる方法と言います。時間ベースではありません。つまり、ゲーム時間を1秒進めるには、gamelogic()を100回呼び出す必要があります。 'gamelogic()'は、ゲームのスクリーンレンダリングと比較して軽量です。

Ogreには、フレームを描画しようとしているときと、フレームの描画が終了したときにコードに通知する「リスナー」ロジックがあります。フレームレンダリングの直前に 'gamelogic()'を呼び出すと、ゲームプレイは画面のレンダリング速度に大きく影響されますが、これは5fpsから120fpsまで変化する可能性があります。

頭に浮かぶ簡単な解決策は以下のとおりです。「)gamelogic(」最後にレンダリングされたフレームからの経過時間を計算し、呼び出して、次のフレームの前に、この何倍:100 * timeElapsedInSeconds

はしかし、私は "というpressumeそれを行うための正しい方法はマルチスレッドです。 gamelogic()を100回/秒実行する別のスレッドがあります。

2つの別々のスレッド間で競合が発生した場合、これをどのように達成できますか:オーガが画面を同時にレンダリングしている間にガメロジックな画面コンテンツ(3Dオブジェクト座標)を変更します。

事前に感謝します。

答えて

6

これが最初のゲームアプリケーションであれば、結果を達成するためにマルチスレッドを使用すると、最初のゲームに本当に取り組むよりも多くの作業が必要になる可能性があります。ゲームループを同期させ、異なるスレッドでループをレンダリングすることは、解決するのが簡単な問題ではありません。

正しく指摘したように、レンダリング時間はゲームの「スピード」に大きく影響する可能性があります。私はあなたのゲームロジックを設定されたタイムスライス(1/100秒)に依存させないことをお勧めします。現在のフレーム時間に依存するようにします(現在のフレームがレンダリングにどれくらいの時間がかかるかわからないので、最後のフレーム時間です)。

一般的に、私は以下のようなものを書きます(私が書いたものが大幅簡略化です):

float Frametime = 1.0f/30.0f; 
while(1) { 
    game_loop(Frametime);  // maniuplate objects, etc. 
    render_loop();    // render the frame 
    calculate_new_frametime(); 
} 

Frametimeは、現在のフレームがかかったことをcalculcated frametimeである場合。ゲームループを処理する場合、前のフレームからのフレーム時間を使用しています(したがって、初期値を1/30または1/15秒のような妥当な値に設定します)。以前のフレームタイムで実行すると、必要な結果が得られます。その時間枠を使用してゲームループを実行し、次にあなたのものをレンダリングします。一定の時間間隔を想定しないようにゲームループ内のロジックを変更する必要があるかもしれませんが、一般にそのような修正はかなり簡単です。

非同期ゲーム/レンダーループが最終的に必要なものかもしれませんが、解決するのは難しい問題です。オブジェクトとその関連データのスナップショットを作成し、そのスナップショットをバッファに入れ、バッファをレンダリングエンジンに渡します。そのメモリバッファは、レンダリングループが読み込まれている間にゲームループに書き込まれることを避けるために、クリティカルセクションの周りで正しく分割されなければならない。レンダリングループに渡す前に、関連するすべてのデータをバッファにコピーするよう注意しなければなりません。さらに、どちらか一方が完了するのを待っている間に、ゲームまたはレンダリングループをストールするロジックを記述する必要があります。

この複雑さは、私が最初に(あなたが経験したことがない限り)それをよりシリアル形式で書くことを提案する理由です。その理由は、まず「簡単な」方法をとることで、コードの仕組み、レンダリングエンジンの仕組み、レンダリングエンジンが必要とするデータの種類などを学ばなければならないからです。複雑なゲーム開発では、マルチスレッドの知識が必要です今日は、それをうまくやり遂げる方法が分かっていれば、ゲームシステムが互いにどのように相互作用するかについての深い知識が必要です。

+1

ゲームは固定レンダリング率の前提から、しばらく前にフレームを追跡することに切り替えられました。以前はプロセッサが8 Hzで動作していることに頼っていました。彼らは16Hzマシンが出てくると、16Hzから8Hzにプロセッサーを切り替えるための「ターボボタン」が含まれているので、ゲームはまだ正しい速度で動いていました。楽しい事実。 – Kieveli

+0

本当に!古いゲームが新しいマシンで許容できるフレームレートで動作するように、あなたのプロセッサを「減速」するよう書かれた小さなアプリもありました。一つは "MOslo"と呼ばれていたと思います。私が持っていた古いコンピュータのすべてで私の古いUltimaゲームが速すぎることを覚えています。 – Mark

+1

ターボ・パスカル・ランタイムでは、高速なマシンで実行しているときに整数オーバーフローが発生し、すべてがクラッシュすることがあります。 – tstenner

0

レンダリング可能なオブジェクトをダブルバッファリングすることは、あなたが探索できるアプローチです。つまり、レンダリングコンポーネントは、すべてのゲームアクションが2番目のバッファ内の関連オブジェクトを更新したときに更新される1つのバッファを使用しています。

私は個人的には好きではありません。私はMarkのアプローチを採用したいと思います。

1

あなたのコアゲームのロジックが、プレイヤーが応答できるよりも速く実行することには、大きな利点はありません。本当に有用な唯一の時間は、速く一定の時間ステップで実行することでシムの動作をより一貫して動作させる物理シミュレーションです。

それ以外にも、フレームごとにゲームループを1回更新し、固定ループに頼るのではなく、可変時間デルタを渡すだけです。マルチスレッドを行うことで得られるメリットは、特にこれがあなたの最初のゲームであれば、コストに比べて最小限です。