2017-10-08 8 views
0

私は純粋なJavaで単純なゲームを作ろうとしていて、描画に問題が発生しました。私は比較的高いフレームレートを維持しようとしていますが、JFrame.repaint()を強制することはできず、次の利用可能な機会にフレームを再描画する要求にすぎません。その結果、以下のコードのフレームレートはひどいものになります。しかし、(これは奇妙な部分です)私のマウスが動いていないときはひどいと思われます。私のマウスが動いていて、ウィンドウの上を覆っていると、フレームレートは速くて鮮明です。純粋なJavaで高いフレームレートでレンダリングするにはどうすればいいですか

私はさまざまなオンラインの提案を試みましたし、これを行う方法の例をコンパイルしました。マウスがウィンドウの上を移動していないとき、フレームレートが劇的に低下するという同じ問題があるようです。

(それが重要ならば、私は、Linuxを使用してんだ)

任意およびすべてのヘルプははるかに高く評価されます!

import java.awt.*; 
import javax.swing.*; 


public class Test extends JPanel { 


    public static void main(String[] args) { 

    JFrame frame = new JFrame(); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setSize(new Dimension(300, 300)); 
    frame.setVisible(true); 
    frame.getContentPane().add(new Test()); 


    for (int k = 0; k < 1_000_000; k++) { 
     frame.repaint(); 
     try { 
     Thread.sleep(10); 
     } catch (InterruptedException e) { 
     e.printStackTrace(); 
     System.exit(1); 
     } 
    } 

    frame.dispose(); 
    System.exit(0); 
    } 



    private int k = 0; 

    public Test() { 
    super(); 
    } 

    @Override public void paintComponent(Graphics g) { 
    super.paintComponent(g); 

    g.setColor(Color.WHITE); 
    g.fillRect(0, 0, getWidth(), getHeight()); 

    g.setColor(Color.BLACK); 
    int height = (int) (((k * 0.01) % 1) * getHeight()); 
    g.drawLine(
     0, height, 
     getWidth(), height 
    ); 

    k++; 

    } 

} 
+2

ご入力ありがとうございました。これはあなたにとって有益な質問です(「ペイント方法であなたの「k」を更新せず、ウォールクロックのベースにしてください)。https://gamedev.stackexchange.com/questions/43347/how-to-handle -frame-rates-and-synchronizing-screen-repaints –

+0

'私のマウスが動いていないときだけひどいと思われます。私のマウスが動いていて、ウィンドウの上が上がっていると、フレームレートは速く、鮮明です。」 - マウスが動いているかどうかにかかわらず、フレームレートは私と同じように見えます。私はWindow 7でJDK8を使用しています。また、コンストラクタでパネルの背景を設定するだけです。バックグラウンドを2回ペイントする必要はありません。 – camickr

+0

簡潔にするために、ちょうどそこにKを入れてください。ゲームははるかに複雑です。私はちょっとしたコードを書いて、レンダリングの更新に関する私の問題を実証しました。しかし、私はgamedevを見てみましょう。ありがとうございました – LeqxLeqx

答えて

1

多くの研究の結果、多くのLinuxシステムでjavaが自動的に表示バッファを同期/フラッシュしないことが判明しました。すべての再ペイントなどは正しいですが、ディスプレイバッファはフラッシングしていないので、奇妙な遅れの影響があります。

ソリューション:

Toolkit toolkit = Toolkit.getDefaultToolkit(); /* get AWT toolkit */ 

/* initialize things */ 
... 

while (your_loop) { 

    /* run your logic */ 
    ... 

    /* paint everything */ 
    ... 

    toolkit.sync(); /* force display buffer to flush */ 
} 

はgamedev.stackexchange.comを見てより良い

1

質問は簡単ではありません。以下のコードはテストされておらず、あなたにアイデアを伝えています。次の行では、AWTがSwingの基礎となります。

まず、paintComponent()を非常に速く(実際に!)保たなければなりません。これが最初の要件です。基本的に60 fpsの場合、15ミリ秒以下で描画する必要があります。透明性やその他のものは忘れてしまいます(Windowsではうまく動作しませんが、Linuxではわかりません)。可能であれば、計算を保存してください。

第2に、他のすべてのスレッドを別のスレッドで実行します。これは自分のプログラムに使用する方法です。 AWTスレッドの外側でラベルを設定してはいけないので、AWTスレッド(もちろんSwingに含まれています)はEventQueue.invokeLater()の呼び出しでカプセル化されている必要があります。

時間がかかるAWTからの入力を受け取ったときにスレッドを作成することを忘れないでください!

第三に、すべてがスムーズに動作するはずtimer

よう
new Timer("Drawer", true).scheduleAtFixedRate(new TimerTak(){ 
    public void run(){ 
     frame.repaint(); 
    } 
}, 
100, // Start in 100 ms 
(int)(1000/60)); // 60 is the frame rate. 

してループを交換してください。すべてだ

// You should initialize just before you create the timer...! 
static private long startedAt = System.currentTimeMillis(); 

@Override public void paintComponent(Graphics g) { 
    super.paintComponent(g); 

    // Microseconds since the game started. 
    long k = (System.currentTimeMillis() - startedAt); 

    // Increment only one by frame (60 fps) 
    k = (int)((double)k * 60/1000.0) 

    // Draw the game...!  
} 

:フレーム数kについては、以下を使用します。コンピュータが十分に強力でない(またはCPUを大量に必要とする、またはガベージコレクタ...)場合、いくつかのフレームを削除できます。しかし、可能であれば、ゲームは最大60 fpsで動作します。

ボーナス:あなたが価値あなたがpaintComponent()を通過するたびに増分する場合、あなたはフレーム数を落としたり秒あたりのフレームの平均数は、実際にゲームを開始してから表示しています。

+0

残念ながら、これはやや良いですが同じ問題が残っています – LeqxLeqx

関連する問題