简体   繁体   中英

Java: Speed up my code

I have been coding an application which renders tiles and GUI and all that. I seem to have come across a problem where my paintComponent seems to hog too much CPU and can no longer run much higher than 10 FPS on my small computer. I was wondering if there was any more efficient way of running this code or threading it or anything to enhance the calculation speed. Here is my code:

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...");
}
}

Also I can tell it is the large loop which kills off about 200 FPS at this point because I commented that part off and my FPS shot up to about 250.

Seems like you could multi-thread some of your outer for-loops at the top of the method, if the Graphics2D instance you are using is thread-safe. Might be worthwhile to keep a ThreadPoolExecutor around for this and then break up your outer for-loops into instances of Runnable. This totally depends on whether or not the order of the draw matters to you - it's hard to tell just from the code you've posted.

One other thing that jumps out at me is how you're accessing your 4-D image array. Recall that multi-dimensional Java arrays are actually arrays of references to other arrays. You'd probably be better off getting a reference to a specific sub-array at the top of each loop, and accessing the sub-array reference that you've saved, rather than indexing the original array directly. This will save you a lot of unnecessary memory fetches.

As a general rule, try to precalculate as much as possible - eg the Strings that you are constructing.

Don't create a new Font on every frame, create it once and reuse it.

As the comments suggest, predraw tiles onto a reusable BufferedImage if that makes sense for your application.

You have quite a few common subexpressions, M0.gameFrame.getHeight() and (32 * zoom) , although the HotSpot compiler may well sort these out if you do repeated runs (a single frame test is no good). It will clarify the code if you factor these out, so is a good thing anyway.

Beyond that, you need to do some profiling to see which parts are taking the most time...

Instead of building new strings (string concatenation) on every repaint, you could cache the strings and only rebuild them if data has changed.

Another idea: draw the static part of each string separately from the dynamic part of the string. You could use FontMetrics to determine the width of certain strings, to help you arrange the dynamic part next to the static part.

Also caching in general is good performance strategy which can be applied in many situations. See eg Bufferedimage .

It seems you redraw the entire screen from scratch each time paintComponent is called.

What would be better is to draw the initial blank image to an offscreen buffer. Each time a tile is updated mark it as dirty. When paintComponent is drawn only redraw the parts of the offscreen buffer which are out of date. That should save you a lot of effort. Then just draw the entire buffer to the screen in one go. Drawing single large images is generally much quicker than drawing lots of small images.

eg.

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM