1

以前の質問で述べたように、私はまだ Java に慣れていません。Java でタイルベースのゲームを開発しています。動きはグリッド上にあります。キャラクターの動きを実装している段階です。

私の計画は、この質問に貼り付けたコードを使用することでした。しかし、これではうまくいかず、SwingWorker を使用するように言われました。

問題解決者として、私はこれについて一日中考えていました。やり方を少し変えることで、同じ効果を得ることができました。

20 ミリ秒ごとにオフになり、再描画を呼び出すタイマーがあると言いました。

私のアイデアは、タイマーのイベントで再描画の前にメソッド呼び出しを行うことができるというものでした。これにより、すべての人が目的地 (次の正方形/タイル) に 1 単位近く移動します。そのようなことは機能しますか?ゲームの後半になると、100 人程度になる可能性があります。すべての人をループして目的地に 1 ユニット近づけるには、20 ミリ秒で十分でしょうか? 20ms は短すぎますか? 私はまったく意味がありませんか?

あなたの意見/回答/考えは大歓迎です:)

4

3 に答える 3

2

私は Bill が言ったことのほとんどすべてに同意します。特に、Swing が謎めいているという部分については (他のグラフィックス環境ほどではありませんが) 同意します。

参考までに、30 fps (ほとんどのインターレース画面で生成される値) は、33 ミリ秒ごとに 1 フレームです。60 fps は人間が知覚できる最高値 (1 フレーム / 16 ミリ秒) であり、ほとんどの LCD モニターは 60 または 75 Hz でリフレッシュされます。20 ミリ秒/フレームは 50 fps のフレーム レートであり、これはヨーロッパ地域の電気周波数とも一致し、人間の目で認識できる程度です。

私が推奨しない主なことは、タイトな while ループですべてを実行することです。これにより、ゲームの速度が、プレイするシステムに大きく依存するようになります。より高速なシステムでは、たとえ古いシステムで適切に再生されたとしても、プレーヤーが反応するよりも速くフレームが吐き出されることがあります (または老朽化し たマシンでは逆の問題が発生します)。タイマーを使用すると、レートをより安定させることができますが、フレームの期限を逃した場合に備えて、いくつかの防御チェックを行う必要があります。これは、タイマーがいつ計算が終了したかを知る必要があることを意味します。そのため、別のフレームがカチカチ音をたてて完了していない場合、次のフレームをスキップします。さらに良いことに、計算の間に実際に経過した時間を記録し、それに応じてキャラクターが移動した実際の動きを調整します。

もう 1 つの警告: 描画は AWT スレッドで実行し、計算は (プログラムの応答性を維持するために) AWT スレッドで実行する必要がありますが、状態も AWT スレッドで更新する必要があります。計算を行うスレッドにゲームの状態を更新させると、AWT スレッドは再描画の途中でこれを確認し、テアリングと呼ばれる効果を引き起こします。したがって、状態のコピーを作成して AWT スレッドにポストする必要がある場合があります。これが SwingWorker の目的であり、おそらく Timer と組み合わせて使用​​します。

驚くべきことに、私が言ったことのほとんどは、あなたの他の質問に投稿したものと比較すると、実際には新しいものです.

于 2009-04-23T17:50:36.673 に答える
2

OK、最初に 20 ミリ秒の質問に答えます。かなり多くのゲーム ロジックを 20 ミリ秒で処理できます。しかし、ディスプレイを更新するにはあまりにも頻繁だと思います。また、OS は一般に 10 ~ 20 ミリ秒のタイムスライスのオーダーで CPU を分配することにも注意してください。つまり、別のプロセスがいつでもその時間だけプロセスを遅らせる可能性があります。たとえば、 Thread.sleep()の動作に関する私の記事を見てください。グラフから、システムが適度にビジーであるため、OS が要求したスリープ時間を尊重できないことがわかります。フレーム間に 100 ミリ秒の平均スリープが必要な場合は、20 ミリ秒程度のジッタがあっても、それほど悪くはありません。しかし、20 ミリ秒を要求したときの 20 ミリ秒のジッターは、おそらくもっと目立つでしょう...

したがって、おそらく 1 秒あたり 10 フレーム (100 ミリ秒の一時停止) から始めて、それがどのように見えるかを確認します。

コードに関する限り、ゲーム ロジックが各ティックに多かれ少なかれ同じ時間を要する場合、各ティックで logic-repaint-sleep から始めます。ペイントしているものを同期する必要があることを忘れないでください。そのため、ゲーム ロジック スレッドでは、理想的にはロックを長時間保持しないようにする必要があります。

于 2009-04-23T17:55:31.500 に答える
1

このスイングの領域は、おそらくJavaで最も「黒魔術」を持っています。トリッキーになる可能性があり、多くのアプローチがあります。

最も重要なルールは、AWTスレッドを使用していない限り、画面を変更しないことですが、画面を変更する以外の目的でAWTスレッドを使用しないでください。

すべてのスイング「コールバック」(ボタンリスナーなど)はAWTスレッドで発生するため、通常はこれについて考える必要はありませんが、アクティブなレンダリング状況では細心の注意を払う必要があります。

通常、このような大規模なシステムでは、計算全体を一度に実行し(すべてのデータを移動)、1つのステップで描画する必要があるすべてのものを再描画します。

したがって、ほとんどの場合、ペイントシステムの外部で継続的なスレッドで計算し、トップレベルのコンポーネントで再ペイント関数を呼び出します。Repaintは、AWTスレッド上のすべてのコンポーネントにペイントイベントを配信する必要があるため、問題にはなりません。

次に、各コンポーネントはその状態(すでに更新されている)を確認し、その情報を使用して自身を描画する必要があります。

これが基本的なやり方ですが、遅くなる可能性があり、スピードアップするためのトリックがたくさんあります。スイングプログラミングとゲームを含む本を探したいと思うかもしれません。

于 2009-04-23T17:21:03.640 に答える