私は単純なゲームを書いています。ループが CPU を消費することなく、フレームレートを 60 fps に制限したいと考えています。どうすればいいですか?
10 に答える
ゲーム ループの記事を読むことができます。何かを実装しようとする前に、まずゲーム ループのさまざまな方法論を理解することが非常に重要です。
@cherouvimが投稿したゲームループの記事を取り上げ、「ベスト」戦略を採用して、Java Runnable用に書き直そうとしましたが、うまく機能しているようです。
double interpolation = 0;
final int TICKS_PER_SECOND = 25;
final int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
final int MAX_FRAMESKIP = 5;
@Override
public void run() {
double next_game_tick = System.currentTimeMillis();
int loops;
while (true) {
loops = 0;
while (System.currentTimeMillis() > next_game_tick
&& loops < MAX_FRAMESKIP) {
update_game();
next_game_tick += SKIP_TICKS;
loops++;
}
interpolation = (System.currentTimeMillis() + SKIP_TICKS - next_game_tick
/ (double) SKIP_TICKS);
display_game(interpolation);
}
}
簡単な答えは、17 ミリ秒ごとに起動するように java.util.Timer を設定し、タイマー イベントで作業を行うことです。
これが私がC++で行った方法です...あなたはそれを適応させることができると確信しています。
void capFrameRate(double fps) {
static double start = 0, diff, wait;
wait = 1 / fps;
diff = glfwGetTime() - start;
if (diff < wait) {
glfwSleep(wait - diff);
}
start = glfwGetTime();
}
capFrameRate(60)
ループごとに 1 回呼び出すだけです。スリープするので、貴重なサイクルを無駄にしません。glfwGetTime()
プログラムが開始されてからの時間を秒単位で返します...Javaのどこかに同等のものがあると確信しています。
Java で FPS を制御するためのタイマーが不正確です。中古で見つけました。独自のタイマーを実装するか、制限付きでリアルタイム FPS を実行する必要があります。ただし、Timer は 100% 正確ではないため、タスクを適切に実行できないため、使用しないでください。
System.currentTimeMillis()
Javaでは、時間をミリ秒単位で取得するために、の代わりに行うことができますglfwGetTime()
。
Thread.sleep(time in milliseconds)
わからない場合に備えてスレッドを待機させます。スレッドはtry
ブロック内にある必要があります。
私が行ったことは、ループを継続し、最後にアニメーションを実行したときを追跡することです。少なくとも 17 ミリ秒経過している場合は、アニメーション シーケンスを実行します。
このようにして、ユーザー入力を確認し、必要に応じて音符のオン/オフを切り替えることができました。
しかし、これは子供たちに音楽を教えるためのプログラムであり、私のアプリケーションはフルスクリーンであるという点でコンピューターを占有していたため、他のアプリケーションではうまく再生できませんでした。
Java Swing を使用している場合、60 fps を達成する最も簡単な方法は、次のように javax.swing.Timer を設定することであり、ゲームを作成する一般的な方法です。
public static int DELAY = 1000/60;
Timer timer = new Timer(DELAY,new ActionListener() {
public void actionPerformed(ActionEvent event)
{
updateModel();
repaintScreen();
}
});
コードのどこかで、このタイマーを繰り返して開始するように設定する必要があります。
timer.setRepeats(true);
timer.start();
1 秒には 1000 ミリ秒があり、これを fps (60) で割り、この遅延 (1000/60 = 16 ミリ秒の切り捨て) でタイマーを設定することにより、ある程度固定されたフレームレートが得られます。これは、上記の updateModel() および repaintScreen() 呼び出しで行う内容に大きく依存するためです。
より予測可能な結果を得るには、タイマーで 2 つの呼び出しの時間を計り、60 fps を維持するために 16 ミリ秒以内に終了するようにしてください。メモリのスマートな事前割り当て、オブジェクトの再利用などにより、ガベージ コレクターの影響も軽減できます。しかし、それは別の質問です。