5

大学の課題のために、ネットワーク対応バージョンの pacman を作成する必要があります。最初に pacman のローカル コピーを作成してから、この機能をネットワーク プレイ用に拡張することで、この問題に対処するのが最善だと考えました。

私は Java GUI 開発に比較的慣れておらず、Java 内でそのような機能を利用していると言わざるを得ません。

Java 内でのゲーム開発と pacman ゲームの例に関して、上記のリンクをたどり始めました。

私は迷路を int 配列として表現することにしました。異なる値は異なる意味を持ちます。ただし、メイン ゲーム ループ内のペイント メソッドが実行されると、このメソッドで迷路全体を再描画しています。

    for (int i : theGame.getMaze())
    {
        if (i == 4)
        {
            g.setColor(mazeWallColour);
            g.fillRect(curX, curY, cellSize, cellSize);
            curX += 25;
        }
        else
        {
            curX += cellSize;
        }

        index++;


        // Move to new row
        if (index == 25)
        {
            index = 0;
            curX = 10;
            curY += cellSize;
        }
    }

ただし、これは1fps未満を提供しています。上記のリンクの例では、paint メソッドが呼び出されるたびに同様の再描画方法を使用していることに気付きましたが、表示できない画像でこれを行うと思います (ダブルバッファリングのようなものです [最初のリンクのように BufferStrategy を使用しました説明します]) 迷路を再描画するより良い方法は何ですか?

これに関するポインタ/アドバイスは役に立ちます。

お時間をいただきありがとうございます。

http://pastebin.com/m25052d5a - メイン ゲーム クラス用。

編集:どのコードが実行に非常に時間がかかっているかを確認しようとした後、非常に奇妙なことが起こっていることに気付きました.

paintClear(Graphics g) メソッドに追加しました

ocean = sprites.getSprite("oceano.gif");
g.setPaint(new TexturePaint(ocean, new Rectangle(0,t,ocean.getWidth(),ocean.getHeight())));
g.fillRect(10, 10,getWidth() - 20,getHeight() - 110);

これにより、すべてがスムーズに実行されました-しかし、これらの行を削除すると、すべてが遅くなりましたか? 何が原因でしょうか?

更新されたコード

4

10 に答える 10

4

まず、コードにランダムなマジック ナンバーを使用するのではなく、名前付き定数を使用し、セル型に列挙型を使用することを検討することをお勧めします。コードの実行が速くなるわけではありませんが、理解しやすくなることは間違いありません。また、「i」は通常、戻り値ではなくカウンターとして使用されます。cellTypeあなたはおそらくそれまたはそれに似たものと呼ぶべきです。また、ステージ マップに 2D 配列を使用することをお勧めします。2D 配列を使用すると、論理的にも概念的にも多くのことが簡単になります。

とはいえ、試してみるべきことがいくつかあります。

ループsetColor()から引き出して、1回行います。コンパイラはループ不変の巻き上げを実行できる可能性があり、したがってこれを実行する可能性があります (おそらくそうするでしょう) が、概念的には、とにかくこれを実行する必要があります。

drawRect()の代わりに呼び出してみてfillRect()、それがより速く描画されるかどうかを確認してください。そうなるとは思いませんが、見栄えが悪くても試してみる価値はあります。同様に、 を作成しImageてから描画することもできます。これには、Graphics オブジェクトに画像の変換を実装するように指示するのが非常に簡単であるという利点があります。また、これを完全に取り除くことを検討し、パフォーマンスが大幅に低下していることを確認してください。

また、通常、Graphics オブジェクトの親を要求して、その上に直接描画を実装する必要はありません。むしろ、そのメソッドをオーバーライドしてpaintComponent()、与えられた Graphics を利用する必要があります (ヘルパー メソッドを呼び出すこともできます)。Swing コンポーネントはデフォルトでダブルバッファリングされるため、自分で実装する必要はありません。スイング オブジェクトに仕事をさせて、いつペイントするかを知らせます。

また、画面全体を再描画することになりますが、これはやり過ぎです。を呼び出すとrepaint(Rectangle)、Swing は、ダーティと明示的にマークされたボードのセクションのみを再描画することを選択できます。スプライトの 1 つを更新するときは、スプライトの古い場所と新しい場所の領域でのみ repaint(r) を呼び出します。レベルをクリアして新しいボードが必要になったら、 repaint() (パラメーターなし) を呼び出してマップ全体を再描画できます。

Sun のチュートリアルも参照して、Swing を効率的に使用するためのヒントを入手してください。

于 2009-01-15T00:07:04.767 に答える
4

私はまだ Java の初心者だと思っていますが、最近、あなたが言及したテクニックのいくつかを使用して、ダイナミック マップとエディターを備えた Frogger 風のゲームを開発しました。

前述のように、列挙型は行く方法です。マップを 2 次元配列として設定し、異なる型ごとに列挙型を設定します。マップ クラス内にメソッドを記述して、1 つの画像を取り込み、マップ内の各正方形を列挙型の各値に分割します。

マッピングに役立つチュートリアルは、Coke and Codeにあります。あなたが何をしているのかをきちんと把握しているように見えますが、それを扱う必要がある場合は、すべてのソースコードがあります。それでも助けが必要な場合は、いつでもソース コードを引き出すことができます。

于 2009-01-15T01:05:01.153 に答える
3

上記のコードが 1fps の問題の原因になることはありません...これよりもはるかに高速に実行されるコードを持っています。

そのコードをベンチマークして、それが問題の原因であることを確認できますか?

于 2009-01-15T00:00:26.260 に答える
3

Thread.sleep の呼び出しが意図したとおりに動作しないようですが、それが問題の原因ではないと思います。あなたが持っている:

Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));

startTime は常に System.currentTimeMillis() よりも小さいため、startTime - System.currentTimeMillis() は常に負になるため、スリープは常に 0 ミリ秒になります。この例では、計算を行う前に startTime を 40 ミリ秒ずつインクリメントするため、示した例とは異なります。描画時間を 40 ミリ秒にパディングするためにスリープする時間を計算しています。

とにかく、あなたの問題に戻ります。どこに時間が費やされているかを把握するために測定することをお勧めします。何が遅いのかがわからない限り、最適化しても意味がありません。System.currentTimeMillis() の使用方法は既に知っています。それを使用して、常にどこに行くかを測定してみてください。壁を描くのにすべて費やされていますか?


編集 - これは承認済みとしてマークされているようですが、スリープ時間を修正したときに問題が解決したと推測する必要がありますか? 私は Java GUI の経験があまりありませんが、おそらくあなたのコードが他の重要なスレッドを枯渇させていたのではないかと推測できます。スレッドを最大の優先度に設定し、sleep(0) のみを呼び出すように設定することで、プロセス内の他のスレッドが何も実行できないことがほぼ保証されます。その理由を説明するRaymond Chen のブログの投稿を次に示します。

于 2009-01-15T01:17:35.903 に答える
2

私はゲーム開発者ではありませんが、そのフレームレートは非常に遅いようです。

あなたのコードがどのように機能しているかはよくわかりませんが、レンダリング パフォーマンスを改善する 1 つの可能性は、あまり変化しないディスプレイの部分 (迷路の壁など) を見つけて、それらを再作成しないようにすることです。各フレーム。

定数要素 (迷路?、背景) を含む BufferedImage を作成し、最初にフレームごとに再描画します。このバッファリングされた画像の上に、可変要素 (パックマン、ゴースト、ドットなど) を描画します。

この手法は、他の多くの Java2D パフォーマンスのヒントとともに、Romain Guy の優れた著書Filthy Rich Clientsで説明されています。

于 2009-01-14T23:58:53.910 に答える
2

Java であることを心配しないでください。私は、GUI 部分全体 (トレース、メニュー、ボタンとホイールの処理) が Java で行われるスペクトル アナライザー (o-scope のようなもの) に取り組みました。そこに着いたときは 1 fps でしたが、離れたときは 12 ~ 20 でした。それは多くの処理が行われており、非常に遅いプロセッサで実行されていました。

更新する必要がある GUI の更新部分だけを見てください。多くの場合、画面全体を再描画できますが、実際に更新される部分にクリッピング領域を設定するだけです.

内側のループには注意してください。それらはスピード キラーです。

膨大な数のオブジェクトを割り当てたり解放したりしないようにしてください。オブジェクトを使用しないと言っているのではなく、ピクセルごとに作成しないでください:)

幸運を

于 2009-01-15T00:05:06.750 に答える
1

可能であれば、迷路の画像を保持し、1回のライブラリ呼び出しで描画する必要があります。おそらくフル解像度である必要はありません。ブロック状の8ビットの感触が必要な場合は、グラフィックライブラリが喜んで8を義務付けることを期待しています^)

また、他の人が述べているように、更新が必要な画面の部分だけを再描画することで時間を節約できます。これは実装が面倒な場合がありますが、フレームレートを大幅に向上させることができる場合があります。必要な努力をする前に、これが事実であることを確認するためにいくつかの実験を必ず行ってください!

于 2009-01-15T01:45:23.570 に答える
1

デフォルトでは Java/Swing ダブルバッファ。Swingを使用している場合、他の回答が示唆するように、個別にダブルバッファリングする必要はありません。

あなたがリストしたコードが1fpsの原因になることはできないというAllainに同意します。あなたが説明するよりもはるかに高速に実行される非常に非効率的な Java/Swing アニメーション コードを作成しました。速度低下の原因を絞り込むために、さらにテストを行います。

于 2009-01-15T00:42:05.990 に答える
1

うわー、Java を学んでいる人に与えるのはかなり難しい問題です。

私のアドバイス?オブジェクトの観点から考えてください。ゲーム自体の動作を模倣するユーザー インターフェイスなしで何かを書くことはできますか? それが機能するようになると、ユーザー インターフェイスの特別な問題に集中できます。はい、ネットワーク化された部分の前にローカル バージョンから始めます。

私はゲーマーではありません。Java2D API があなたの生活をより良くするためにどのようなものを提供してくれるのだろうか?

それを終えるのにどれくらいの時間が必要ですか。

于 2009-01-14T23:23:09.910 に答える
1

これは明白に聞こえるかもしれませんが、パフォーマンスの問題は、迷路全体を再描画しているためです。これを行う必要はありません。代わりに、迷路の変更された部分のみを再描画する必要があります。

私が以前にこの問題に取り組んだ方法は、迷路の更新を実際の再描画から別のスレッド (スレッド化された MVC のようなもの) に分離することでした。迷路のセルを変更するたびに、それを「ダーティ」としてマークします。再描画スレッドは時々チェックして、ダーティ セルのみを再描画します。

非常に一般的なアドバイスで申し訳ありません

于 2009-01-14T23:58:16.983 に答える