[英]Java: Speed up my code
我一直在編寫一個渲染圖塊和GUI的應用程序。 我似乎遇到了一個問題,我的paintComponent似乎占用了過多的CPU,並且在我的小型計算機上無法再以高於10 FPS的速度運行。 我想知道是否有任何更有效的方式來運行此代碼或對其進行線程化或任何其他方式來提高計算速度。 這是我的代碼:
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...");
}
}
我還可以說這是一個大循環,這會殺死大約200 FPS,因為我評論了該部分,而我的FPS飆升至大約250。
如果您使用的Graphics2D實例是線程安全的,則似乎可以在方法頂部對某些外部for循環進行多線程處理。 可能值得為此保留一個ThreadPoolExecutor,然后將外部for循環分解為Runnable實例。 這完全取決於抽簽的順序對您來說是否重要-僅從您發布的代碼中很難分辨出來。
讓我驚訝的另一件事是您如何訪問4-D圖像陣列。 回想一下,多維Java數組實際上是對其他數組的引用的數組。 您最好在每個循環的頂部獲取對特定子數組的引用,並訪問已保存的子數組引用,而不是直接為原始數組建立索引。 這將節省大量不必要的內存獲取。
作為一般規則,請嘗試盡可能多地進行預先計算-例如,您正在構造的字符串。
不要在每個框架上都創建一個新的Font
,只能創建一次並重復使用。
正如評論所建議的,如果對您的應用程序有意義,則將圖塊預繪制到可重用的BufferedImage上。
您有很多常見的子表達式M0.gameFrame.getHeight()
和(32 * zoom)
,盡管如果您重復運行,HotSpot編譯器很可能會解決這些問題(單幀測試是不好的)。 如果您將這些因素排除在外,它將澄清代碼,所以還是一件好事。
除此之外,您還需要進行一些分析,以了解哪些部分花費了最多的時間...
您可以緩存字符串並僅在數據已更改時重建它們,而不是在每次重畫時都構建新的字符串(字符串連接)。
另一個想法:將每個字符串的靜態部分與字符串的動態部分分開繪制。 您可以使用FontMetrics確定某些字符串的寬度,以幫助您將動態部分排列在靜態部分的旁邊。
一般而言,緩存也是一種可以在許多情況下應用的良好性能策略。 參見例如Bufferedimage
。
似乎每次調用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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.