更新にターンベース(RPG)ゲームでアイドル時間を使用する


9

ターンベースのRPGゲームを実行すると、ゲームが「wait_for_player_input」をループしているため、何も起こらない時間が長くなります。当然、この時間を使用して更新するのが賢明なようです。

ただし、これはすぐにスレッド化する必要があることを示唆しているようです。この種の設計は単一のスレッドで可能ですか?

loop:  
if not check_something_pressed:  
    update_a_very_small_amount  
else  
  keep going

しかし、「a_very_small_amount」がループごとに1つのオブジェクトのみを更新していると言うと、更新が非常に遅くなります。

あなたはこれについて、できればシングルスレッドでどうしますか?

編集:私はこの言語にとらわれないタグを付けました。;-)

2番目の編集:このゲームでは、アニメーションコンポーネントを使用する予定はありません。つまり、私は現在、プレイヤー入力待ちとして実行しており、すべてを更新して描画しています。したがって、X FPSではなく、ユーザーの速度に依存します。

回答:


7

はい、単一のスレッドで実行できます。ただし一般的に言えば、スペアサイクルがある場合だけでなく、フレームごとにオブジェクトを更新する必要があります。アニメーションと動きはフレームレートから切り離され、そうしないとかなり不安定になります。AIの更新など、リアルタイムである必要のないものについて詳しく説明している場合は、タイマーを設定します。ターゲットフレームレートが何であるかを知っている必要があり、アイドル時間は、他のすべてが完了した後に残っているものになります。

ゲームのターゲットを60 FPSにするとします。これにより、各フレームを実行するために必要なすべての作業を実行するための16.667ミリ秒が残ります。ゲームの開始時に、利用可能な最も高い解像度のタイマーを使用して現在の時刻を取得し、16.667 msを追加して、どこかに保存します。Pythonでの関数はtime()だと思いますが、言語で働いてからしばらく経ちます。処理が完了したら、現在の時刻を記録した時刻と照合するループに入ります。現在の時刻がフレームの終了時刻よりも短い場合は、update_a_very_small_amount。小さな更新は迅速に処理されるはずなので、フレームの終わりを過ぎても処理が心配されることはありません。次のフレームの開始までの遅延はわずかであり、それを処理するのに十分なアイドル時間があるように見えます。

フレームの処理が完了したら、最後のフレームの終わりに格納された時間に16.667 msを追加して、次のフレームの終わりがどこにあるかを確認します。現在の時間+ 16.667ミリ秒を使用して処理が終了すると、次のフレームの終わりは、最後のフレームがオーバーした時間だけ押し出されます。

Re:2番目の編集

明確にするために、ここではフレームレートという用語を使用して、メインループの1回の反復を示しています。それがユーザーの入力速度に基づいている場合、私はあなたの目標が単にゲームの応答性を感じさせることだと想像します。それ以外の場合は、入力をチェックして、ループに毎回すべてを更新することができます。たとえそれを行うのに10秒かかる場合でもです。ただし、応答性を高めるために、実際にこれらのフレームを描画していない場合でも、20 FPSの実効フレームレートを提供する1秒あたり約20回の入力を確認する必要があります。これにより、入力を再度チェックする前に、50ミリ秒で更新されます。


2

特にPythonではコルーチンを使用して、複数の更新呼び出しで計算を実行できます。

...コルーチンは、特定の場所で実行を一時停止および再開するための複数のエントリポイントを許可するようにサブルーチンを一般化するプログラムコンポーネントです...

PEP-0342は、Pythonでのコルーチンの実装を詳しく説明しています。

単一のスレッドでマルチスレッドをシミュレートできる独自のスケジューラとタスクを作成できます。これは、JavaScriptが単一のプロセスで実行されている場合でも、JavaScriptフレームワークがマルチスレッドのような処理を可能にするのと同じ方法です。


1

はい、可能です。ゲームには、何らかのメインゲームループがあります。このようなもの:

while(gameRunning)
{
  checkUserInput()
  updateGame()
  renderGame()
}

updateGameでは、ゲームオブジェクトを反復処理して「少し」更新できます。この方法で重い計算を行っている場合、ゲームは単純にハングします。したがって、これらの計算を分割して、ゲームループの複数の反復を実行する方法が必要です。

それらを分割する方法は、構築しているゲームの種類によって異なります。A *を使用して迷路のパスを計算するパスファインダールーチンがあるとします。一定の時間が経過した後、または一定量の反復の後、アルゴリズムを停止し、計算されたパスをここまで維持して、制御をゲームループに戻す必要があります。パスの検索は、次にupdateGameが呼び出されたときに続行されます。まだ計算されている間に、部分パスに沿ってキャラクターを移動することもできます。

ほとんどの場合、updateGame呼び出しに時間がかかりすぎることを心配する必要はありません。

「時期尚早の最適化がすべての悪の根源です!」
更新ルーチンでパフォーマンスのボトルネックが発生した場合は、調査して最適化する必要があります。ゲームのどの部分が計算に最も時間がかかるかを事前に知ることができず、間違ったものを最適化するのに時間を浪費する可能性があるためです。


1

私があなたの質問を理解する方法は、基本的には協調マルチタスクについて尋ねているということです。

基本的なインフラストラクチャは関数ポインタのリストであり、すべてラウンドロビン方式で呼び出され(より高度な優先順位付けが必要な場合を除く)、これらのすべての関数は「少しの作業」を行います。遅くなる。これは、スレッドがホットになる前のDOS、およびスレッド化をサポートしていないモバイルデバイスでも行っています。

私の意見では、より良い質問は、プレイヤーが動くのを待つ間に何をすべきかです。どのような種類のものがプロセッサに負荷がかかり、とにかくその場で実行することができないか、同時にオプションであるので、プレーヤーが移動キーを十分速く打った場合、ゲームにはありません。これらを処理する時間。したがって、数千のAIのA *を計算するようなものはなくなりました。

私の意見では、より良い解決策は、単に制御を放棄/スリープさせて、コンピューターの電源管理にその仕事を任せることです。ラップトップユーザーは、あなたのことをもっと好きになるでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.