2012-03-13 91 views
0

我一直在編寫一個應用程序來渲染圖塊和GUI以及所有這些。我似乎遇到了一個問題,那就是我的paintComponent似乎佔用了太多CPU,並且在我的小型計算機上運行速度不能超過10 FPS。我想知道是否有更有效的方式來運行這個代碼或者通過線程來提高計算速度。這裏是我的代碼: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 2012-03-13 21:59:52

+2

灰色,他的大部分答案其實都沒有答案:S – Augusto 2012-03-13 21:59:54

+0

如果有人願意幫助我,那麼他們會幫助我。 – MrDrProfessorTyler 2012-03-13 22:00:37

回答

2

好像你可以在方法的頂部多線程一些外部的for-loops,如果你使用的Graphics2D實例是線程安全的。可能需要爲此保留一個ThreadPoolExecutor,然後將外部的for-loop分解爲Runnable的實例。這完全取決於抽獎的順序是否與你有關 - 很難僅從你發佈的代碼中知道。

另一件跳出我的是你如何訪問你的4-D圖像數組。回想一下,多維Java數組實際上是對其他數組的引用的數組。您可能會更好地獲取每個循環頂部的特定子數組的引用,並訪問您保存的子數組引用,而不是直接對原始數組編制索引。這將爲您節省大量不必要的內存提取。

+0

我怎麼可以線程for循環,並仍然測試其中的一切?我從來沒有聽說過能夠做到這一點... – MrDrProfessorTyler 2012-03-13 22:33:57

+0

你必須實現Runnable。在您的自定義Runnable實現中,您必須保持告訴Runnable它所代表的for循環的迭代狀態。將你的Runnable實例傳遞給新的線程或由ThreadPoolExecutor管理的現有線程 - 你的選擇 - 你只需要確保你等待那些線程完成你提交的每個Runnable,這樣你就可以保證當你完成繪製時繪製方法返回。 – CodeBlind 2012-03-13 22:39:08

+0

好聽起來不錯我會盡力謝謝! – MrDrProfessorTyler 2012-03-13 22:45:02

1

作爲殺死了大約200 FPS在這一點上一般的規則,儘量預先計算 - 例如您正在構建的字符串。

不要在每一幀上創建一個新的Font,創建一次並重用它。

正如評論所暗示的,如果這對於您的應用程序來說是合理的,請將tile預渲染到可重用的BufferedImage上。

你有好幾個常見的子表達式,M0.gameFrame.getHeight()(32 * zoom),雖然熱點編譯器可以以及這些整理出來,如果你重複運行(單個幀的測試是沒有好)。如果你將這些因素分解出來,它將澄清代碼,無論如何,這是一件好事。

除此之外,你需要做一些分析,看看哪些部分最耗時...

+0

好主意,我已經嘗試了大部分,但是用於預繪製的BufferedImage全部都會破壞我的FPS而不是循環和其他所有內容。 – MrDrProfessorTyler 2012-03-13 22:31:16

+0

這可能會有所幫助,我會嘗試一下。感謝您的幫助 – MrDrProfessorTyler 2012-03-13 22:45:33

1

而是在每一個重繪建設新的字符串(字符串連接),你可以緩存字符串,只有重建他們如果數據發生了變化。

另一個想法:將每個字符串的靜態部分與字符串的動態部分分開繪製。您可以使用FontMetrics確定某些字符串的寬度,以幫助您將動態部分排列在靜態部分旁邊。

一般來說,緩存也是很好的性能策略,可以在很多情況下應用。見例如Bufferedimage

+0

我如何緩存字符串而不是重建它們? – MrDrProfessorTyler 2012-03-13 22:34:25

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); 

}