1

簡単なスペースシューターを書く予定です。repaint() メソッドは単なるリクエストであり、呼び出されるたびに実行されるわけではないことを読みました。宇宙船を動かしているときに宇宙船がわずかに遅れる傾向があるため、これの影響に気付いていると思います。現在、私は単純に JPanel の paintComponent() メソッドで自分の船を描いており、定期的に repaint() を呼び出し続けています (私のパネルも Runnable です)。repaint() が私を台無しにする可能性があるので、それを回避する方法を見つけようとしていますが、アイデアが不足しています。私がこれまでに持っているコード:

private void renderGraphics() {
    if (MyImage == null) {
        MyImage = new BufferedImage(getPreferredSize().width,
                getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
    }
    MyGraphics = MyImage.getGraphics();
    MyGraphics.setColor(Color.BLACK);
    MyGraphics.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
    MyGraphics.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);       
}

アイデアは、独自のグラフィックを作成し、JPanel に描画させ、run() メソッドで repaint() の代わりにこれを呼び出し続けることでしたが、その方法がわかりません。この件に関するご意見をお待ちしております。

4

6 に答える 6

4

これにアプローチする方法は複数あります。

最善の方法は、おそらくそれを使用BufferStrategyして描画することです。そのコード スニペットを含めました。

Frame/BufferStrategy を使用するだけで、これをさらに一歩進めることができ、Swing を完全に放棄することができます。私の質問には、完全に機能する例(コードスニペットが取得され、適応されたもの)があります:

AWT カスタム レンダリング - スムーズなサイズ変更をキャプチャし、サイズ変更のちらつきをなくします

とにかく、ここBufferStrategyにあなたが立ち寄ることができるはずの実装があります:

// you should be extending JFrame
public void addNotify() {
    super.addNotify();
    createBufferStrategy(2);
}

private synchronized void render() {
    BufferStrategy strategy = getBufferStrategy();
    if (strategy==null) return;
    sizeChanged = false;
    // Render single frame
    do {
        // The following loop ensures that the contents of the drawing buffer
        // are consistent in case the underlying surface was recreated
        do {
            MyGraphics draw = strategy.getDrawGraphics();
            draw.setColor(Color.BLACK);
            draw.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
            draw.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
            draw.dispose();

            // Repeat the rendering if the drawing buffer contents 
            // were restored
        } while (strategy.contentsRestored());

        // Display the buffer
        strategy.show();

        // Repeat the rendering if the drawing buffer was lost
    } while (strategy.contentsLost());
}
于 2011-08-01T10:22:48.897 に答える
2

描画は引き続き Swing スレッドで実行されるため、何を回避しようとしても役に立ちません。

Swing スレッドで長い計算を行っていないことを確認してください。これにより、再描画が必要になったときにすぐに再描画の実行が停止する可能性があります。

于 2011-08-01T10:07:08.407 に答える
2

すべてのロジックを 2 つの部分に分けます。静的および動的。(例:海と動く船。海の静止画像上で船の形や位置が変わる)

画像に静的コンテンツを一度描画し、その画像を paintComponent() で使用します。静止画の後に動的パーツ塗装を呼び出します。

再描画領域を制限するには、setClip() を使用します。

于 2011-08-01T10:07:19.530 に答える
2

ここに投稿するコードのみ:

1/ Image/ImageIconを表示したい場合、最も簡単な方法はラベルを使用することです

2/あなたが言及したように、Runnable{...}.start();Swingは単純なスレッド化されており、GUIへのすべての出力はEDTで行う必要があります。Concurrency in Swingを確認する必要があります。その結果、 からのすべての出力をBackGround Task(s)にラップする必要がinvokeLater()あります。パフォーマンスに問題がある場合は、 にinvokeAndWait()

3/ (間でJComponents) 切り替え/追加/削除/変更するLayout場合はrevalidate() + repaint()、具体的なコード ブロックの最後の行として呼び出す必要があります。

編集:

汚いハックはpaintImmediately()になります

于 2011-08-01T10:24:11.813 に答える
2

引数なしで repaint を呼び出すと、パネル全体が再描画されます。

画面の一部を再描画する必要がある場合 (宇宙船が別の場所に移動した場合)、画面のそれらの部分のみが再描画されることを確認する必要があります。同じままの領域は触れないでください。

Repaint は、再描画する四角形の座標を取ります。船を移動するときは、船の古い座標と移動先の座標を知っておく必要があります。

repaint( oldShipCoordinateX, oldShipCoordinateY, shipWidth, shipLength );
repaint( newShipCoordinateX, newShipCoordinateY, shipWidth, shipLength );

これは通常、引数なしで repaint() を呼び出すよりもはるかに高速です。ただし、船の最後の位置を覚えておくには特別な努力が必要であり、船の新しい位置を計算できなければなりません。

参照: http://download.oracle.com/javase/tutorial/uiswing/painting/index.html - 特に手順 3

于 2011-08-01T10:25:24.233 に答える
1

repaint() メソッドは単なるリクエストであり、呼び出されるたびに実行されるわけではないことを読みました

複数の repaint() リクエストを 1 つに統合して、効率を高めます。

宇宙船を動かしているときに宇宙船がわずかに遅れる傾向があるため、これの影響に気付いていると思います。

次に、この問題を示す SSCCE を投稿してください。問題はあなたのコードだと思います。

あなたが受け入れた解決策については、Charles の最後の投稿をご覧ください: Swingと AWT のソリューションを比較する EDT の外でレンダリングするための Swing/JFrame と AWT/Frame 。

于 2011-08-01T15:01:51.573 に答える