2012-03-13 20 views
0

私は、タイルとGUIとそのすべてをレンダリングするアプリケーションをコーディングしています。私はpaintComponentがあまりにも多くのCPUを必要とし、私の小さなコンピュータではもはや10 FPSよりもはるかに高いCPUを走らせることができないという問題に遭遇したようです。私は、このコードを実行するための効率的な方法があるのか​​、それとも何かを計算する速度を向上させるためのものがあるのか​​どうか疑問に思っていました。ここに私のコードは次のとおりです。Java:コードを高速化

import java.awt.Color; 
import java.awt.Font; 
import java.awt.Graphics; 
import javax.swing.JPanel; 

@SuppressWarnings("serial") 
public class M1 extends JPanel implements Runnable { 
public static double zoom = 1.25; 
public static double charZoom = 1; 
public static boolean breaking = false; 

public void run() { 

} 

public void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    if(zoom <= 0.03) zoom = 1.25; 

    for(int cy = 0; cy < 3; cy++) { 
     for(int cx = 0; cx < 3; cx++) { 
      for(int y = 0; y < 16; y++) { 
       for(int x = 0; x < 16; x++) { 
        g.drawImage(Tiles.tileImages.get(C0.chunk[x][y][cx][cy]), 
          (int)((C0.cX[cx][cy] * C0.chunkWidth) * zoom) + ((int)(32 * zoom) * x) + 
           ((M0.gameFrame.getWidth()/2)) - (int)(PEntity.x.getValue() * zoom), 
          (int)((C0.cY[cx][cy] * C0.chunkHeight) * zoom) + ((int)(32 * zoom) * y) + 
           ((M0.gameFrame.getHeight()/2)) - (int)(PEntity.y.getValue() * zoom) + (int)(24.25 * zoom),// <-- 24.25 used to correctly position charatcter 
          (int)(32 * zoom), (int)(32 * zoom), this); 
        if(C0.chunk[x][y][cx][cy].equals("a05")) { 
         g.drawImage(Tiles.treetop, 
           (int)((C0.cX[cx][cy] * C0.chunkWidth) * zoom) + ((int)(32 * zoom) * x) + 
            ((M0.gameFrame.getWidth()/2)) - (int)(PEntity.x.getValue() * zoom), 
           (int)((C0.cY[cx][cy] * C0.chunkHeight) * zoom) + ((int)(32 * zoom) * y) + 
            ((M0.gameFrame.getHeight()/2)) - (int)(PEntity.y.getValue() * zoom) + (int)(24.25 * zoom) 
            - (int) (32 * zoom),// <-- 24.25 used to correctly position charatcter 
           (int)(32 * zoom), (int)(32 * zoom), this); 
        } 
       } 
      } 
     } 
    } 

    if(breaking) { 
     g.drawImage(M3.currentBreak, (int)((C0.cX[M3.cx][M3.cy] * C0.chunkWidth) * zoom) + ((int)(32 * zoom) * M3.x) + 
       ((M0.gameFrame.getWidth()/2)) - (int)(PEntity.x.getValue() * zoom), 
       (int)((C0.cY[M3.cx][M3.cy] * C0.chunkHeight) * zoom) + ((int)(32 * zoom) * M3.y) + 
       ((M0.gameFrame.getHeight()/2)) - (int)(PEntity.y.getValue() * zoom) + (int)(24.25 * zoom), 
       (int)(32 * zoom), (int)(32 * zoom), this); 
    } 

    M3.placeX = (48 * zoom); 
    M3.placeY = (48 * zoom); 

    if(M0.HUDenabled) { 
     g.drawImage(PEntity.currentChar, 
       (M0.gameFrame.getWidth()/2) - (int)((16 * charZoom) * zoom), 
       (M0.gameFrame.getHeight()/2) - (int)((32 * charZoom) * zoom), 
       (int)((32 * charZoom) * zoom), (int)((64 * charZoom) * zoom), this); 

     g.setColor(Color.BLACK); 
     g.setFont(new Font("Dialog", 1, 12)); 
     g.drawString("Terrem" + " By Tyler D :)", 5, 15); 
     g.drawString("X: " + PEntity.x.getValue(), 5, 28); 
     g.drawString("Y: " + PEntity.y.getValue(), 5, 41); 
     g.drawString("ChunkX: " + C0.currentChunkX.getValue(), 5, 54); 
     g.drawString("ChunkY: " + C0.currentChunkY.getValue(), 5, 67); 
     g.drawString("BlockX: " + C0.currentBlockX.getValue(), 5, 80); 
     g.drawString("BlockY: " + C0.currentBlockY.getValue(), 5, 93); 
     g.drawString("Zoom: " + zoom, 5, 106); 
     g.drawString(M4.tileArea[0][0] + "_" + M4.tileArea[1][0] + "_" + M4.tileArea[2][0], 5, 126); 
     g.drawString(M4.tileArea[0][1] + "_" + M4.tileArea[1][1] + "_" + M4.tileArea[2][1], 5, 139); 
     g.drawString(M4.tileArea[0][2] + "_" + M4.tileArea[1][2] + "_" + M4.tileArea[2][2], 5, 152); 
     g.drawString("FPS: " + (int) FPS.currentFPS, 5, 172); 

     //GUI 
     g.drawImage(M0.GUIbar, (M0.gameFrame.getWidth() - (624))/2, (M0.gameFrame.getHeight() - 80), 624, 40, this); 
     for(int i = 0; i < 9; i++) { 
      g.drawImage(Item.Item_Img.get(PEntity.PInv[i]), ((M0.gameFrame.getWidth() - (624))/2) + 6 + (36 * i), 
        (M0.gameFrame.getHeight() - 74), 28, 28, this); 
      if(Item.Item_Img.get(PEntity.PInv[i]) != null) { 
       g.drawString("" + (PEntity.stk[i] + 1), ((M0.gameFrame.getWidth() - (624))/2) + 6 + (36 * i), 
         (M0.gameFrame.getHeight() - 47)); 
      } 
     } 
    } 

    repaint(); 
    FPS.calculateFrameRate(); 
} 

public M1() { 
    M0.gameFrame.setVisible(true); 
    Clock.Start(); 
    setBackground(new Color(242, 220, 121)); 
    System.out.println("M1 loaded..."); 
} 
} 

また、私は私がパートオフと私のFPSを約250

+1

すべての文字列建物を削除すると、どのくらい速く実行されますか? – RussS

+2

グレー、彼の答えのほとんどは実際には未回答です:S – Augusto

+0

誰かが私を助けてくれるのであれば、彼らは私を助けます。 – MrDrProfessorTyler

答えて

2

あなたが使用しているGraphics2Dインスタンスがスレッドセーフである場合、メソッドの最上部にいくつかの外側のfor-loopsをマルチスレッドすることができるようです。これのためにThreadPoolExecutorを保持しておき、外部のforループをRunnableのインスタンスに分割することは価値があります。これは、抽選の順序があなたにとって重要かどうかにかかっています。投稿したコードだけでは分かりません。

私に飛び出したもう1つのことは、あなたの4-Dイメージアレイへのアクセス方法です。多次元Java配列は、実際には他の配列への参照配列です。おそらく、元の配列を直接索引付けするのではなく、各ループの先頭にある特定のサブ配列への参照を取得し、保存したサブ配列参照にアクセスする方が良いでしょう。これにより、不要なメモリフェッチがたくさん保存されます。

+0

どうすればfor-loopsをスレッド化し、それらの内部のすべてをテストすることができますか?私は以前にそれを行うことができることを聞いたことがない... – MrDrProfessorTyler

+0

Runnableを実装する必要があります。あなたのカスタムRunnable実装では、Runnableにどのforループが反復されたかを伝える状態を維持する必要があります。 Runnableのインスタンスを新しいスレッドに渡すか、ThreadPoolExecutorで管理されている既存のThreadPoolExecutorに渡します。あなたが選択したRunnableを完了するのを待っていることを確認してください。 paintメソッドが返されました。 – CodeBlind

+0

よく聞こえますよそれを試してみましょう! – MrDrProfessorTyler

1

ように急上昇とコメントしているため、それはこの時点で約200 FPSをオフに殺す大きなループで伝えることができます原則として、可能な限り事前に計算してみてください。あなたが構築しているStrings。

すべてのフレームに新しいFontを作成しないでください。一度作成して再利用してください。

コメントが示唆しているように、再利用可能なBufferedImageにタイルをプレデクリメントすると、アプリケーションにとって意味をなされます。 HotSpotのコンパイラがうまくあなたが繰り返されない場合の実行を、これらを整理かもしれないが

あなたは、かなりの数の共通部分式、M0.gameFrame.getHeight()(32 * zoom)を持っている(単一フレームのテストは無意味です)。とにかくこれらを除外すればコードを明確にするので、良いことです。

その向こう

、あなたが最も時間を費やしている部分を参照するためにいくつかのプロファイリングを行う必要があります...

+0

良いアイデアと私はそれらの大部分を試しましたが、それをプレビューするためのBufferedImageはすべてループと他のすべてよりも私のFPSを破壊します。 – MrDrProfessorTyler

+0

これは少し試してみるのを助けるかもしれません。ヘルプありがとう – MrDrProfessorTyler

1

代わりに、すべての再描画に新しい文字列(文字列連結)を構築するの、あなたは文字列をキャッシュし、唯一の再構築ができデータが変更された場合

別の考え方:各文字列の静的部分を文字列の動的部分とは別に描画します。 FontMetricsを使用して特定の文字列の幅を判断し、静的部分の横に動的部分を配置するのに役立てることができます。

また、一般にキャッシュは、多くの状況で適用できる優れたパフォーマンス戦略です。例えば、 Bufferedimage

+0

文字列を再構築するのではなく、どうやってキャッシュすることができますか? – MrDrProfessorTyler

1

paintComponentが呼び出されるたびに画面全体を最初から再描画しているようです。

最初の空白イメージをオフスクリーンバッファーに描画する方がよいでしょう。タイルが更新されるたびに、ダーティーとしてマークします。 paintComponentが描画されるとき、オフスクリーンバッファの古い部分のみを再描画します。それはあなたに多くの労力を節約するはずです。次に、バッファ全体を一度に画面に描画します。単一の大きな画像を描くことは、多くの小さな画像を描くことよりも一般にはるかに迅速です。

例えば、

public void paintComponent(Graphics g) { 

    updateOffscreenBuffer(); 
    // ^-- contains all the nested for loops, but does minimal work 

    g.drawImage(getOffscreenBuffer()); 
    // ^-- draw the entire buffer all in one go to the screen 

    drawHUD(g); 

}