简体   繁体   中英

Java: How can I draw these images faster?

Ok so I am making a game where the user moves an image(called "map" in my code) behind the character in the game so it appears as though the character is moving.

While the program is running, there are moderate performance drops, and the background image("map") lags and is not always repainted.

Here is a class that my main class calls to paint the pictures:

public graphics(int z,int s, int f)
{
    x = z;
    y = s;
    d = f;
    try {
    map = ImageIO.read(new File("background.png"));
    //br = ImageIO.read(new File("blackrectangle.jpg"));
    s0 = ImageIO.read(new File("spriteshoot0.png"));
    s10 = ImageIO.read(new File("spriteshoot10.png"));
    s20 = ImageIO.read(new File("spriteshoot20.png"));
    s30 = ImageIO.read(new File("spriteshoot30.png"));
    s40 = ImageIO.read(new File("spriteshoot40.png"));
    s50 = ImageIO.read(new File("spriteshoot50.png"));
    s60 = ImageIO.read(new File("spriteshoot60.png"));
    s70 = ImageIO.read(new File("spriteshoot70.png"));
    s80 = ImageIO.read(new File("spriteshoot80.png"));
    s90 = ImageIO.read(new File("spriteshoot90.png"));
    s100 = ImageIO.read(new File("spriteshoot100.png"));
    s110 = ImageIO.read(new File("spriteshoot110.png"));
    s120 = ImageIO.read(new File("spriteshoot120.png"));
    s130 = ImageIO.read(new File("spriteshoot130.png"));
} catch (IOException e) {}
}
public void moveZ(int a,int b)
{
    xz+=a;
    yz+=b;
}

public void move(int a,int b)
{
    x+=a;
    y+=b;
}

public void angle(int t)
{
    q=t;

}



public void paintComponent(Graphics g) {

        g.drawImage(map,x,y,this);

        if (q==1)
        g.drawImage(s0,599,340,null);

        if (q==2)
        g.drawImage(s10,599,340,null);

        if (q==3)
        g.drawImage(s20,599,340,null);

        if (q==4)
        g.drawImage(s30,599,340,null);

        if (q==5)
        g.drawImage(s40,599,340,null);

        if (q==6)
        g.drawImage(s50,599,340,null);

        if (q==7)
        g.drawImage(s60,599,340,null);

        if (q==8)
        g.drawImage(s70,599,340,null);

        if (q==9)
        g.drawImage(s80,599,340,null);

        if (q==10)
        g.drawImage(s90,599,340,null);

        if (q==11)
        g.drawImage(s100,599,340,null);

        if (q==12)
        g.drawImage(s110,599,340,null);

        if (q==13)
        g.drawImage(s120,599,340,null);

        if (q==14)
        g.drawImage(s130,599,340,null);
   }}

So I am wondering how I can display the image "map" faster or find an alternate route around this performance issue.

Note* * This code is created as an object in my main class and the BufferedImages aren't being read from the files every single time this is executed(as far as I know). Also, the repaint(); method is called at every 16 milliseconds in my program (and yes i've tried increasing that time and the issues still remain). Here is a snippet of the timer used to repaint the frame:

TimerTask task = new TimerTask() {

    public void run()       {

        if (onU)
            g.move(0,3);

        if (onL)
            g.move(3,0);

        if (onD)
            g.move(0,-3);

        if (onR)
            g.move(-3,0);
        //System.out.println(ze.getX(650,400,650,0,xZ,yZ));
        //System.out.println(ze.getY(650,400,650,0,xZ,yZ));
        if(onR||onL||onD||onU)
        gameSurface.repaint();
    }};

Any help is greatly appreciated, thanks.

Consider limiting your repaint(...) to the small area of the GUI that needs to be repainted. Also and again, don't dispose the Graphics object passed to you by the JVM in the paint or paintComponent method. Only dispose one you've created yourself.

Edit 1
If performance of graphics is the key, you may be better off leaving Swing and moving to a library that is optimized for games, animations, and graphics.

You can cache frequently used images via ResourceBundle. The following code provides cache access to images stored in a jar or in absolute path as ImageIcons. First time access with will store an image into a Hashtable. Subsequent calls to the same image will be a lookup. This class must be set under "default" package:

import java.util.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.*;

import javax.imageio.ImageIO;
import javax.swing.*;

/**
 * ImageBundle is a ResourceBundle that retrieves the content of an image from an image file with supported extension.
 */
public class ImageBundle extends ResourceBundle {
    private static final String RESOURCE = "MyApp";
    private String __fileSuffix;
    /**
     * @uml.property  name="__KEYS"
     */
    private static final Vector<String> __KEYS;
    private static Hashtable<String, ImageIcon> __TABLE;

    static {
        __KEYS  = new Vector<String>();
        __KEYS.addElement(RESOURCE);
        __TABLE = new Hashtable<String, ImageIcon>();
    }

    /**
     * Load image file stored in a JAR classpath
     * @param imageName the filename of the image
     * @return the ImageIcon of the image file
     */
    private ImageIcon __loadImageFromJar(String imageName) {
        String path = ""; //define the file path of the image file in imageName itself

        String imagePath = path + imageName + __fileSuffix;
        ImageIcon icon;
        URL url;

        icon = (ImageIcon)__TABLE.get(imageName);

        if(icon != null)
            return icon;

        url = ImageBundle.class.getResource(imagePath);

        icon = new ImageIcon(url);
        __TABLE.put(imageName, icon);

        return icon;
    }

    /**
     * Load image file stored in a given path
     * @param imageName the filename of the image
     * @return the ImageIcon of the image file
     */
    @SuppressWarnings("unused")
    private ImageIcon __loadImageFromExternalSource(String imageName) {
        String path = System.getenv("MY_APP_HOME_PATH");

        String imagePath = ((path != null) ? (path + imageName + __fileSuffix) : (imageName + __fileSuffix));
        ImageIcon value;

        value = (ImageIcon)__TABLE.get(imageName);

        if(value != null){
            //Outils.debugMessage("Cached " + imagePath + "> " + imageName + ": " + value);
            return value;
        }
        else {
            //Outils.debugMessage("New " + imagePath + "> " + imageName + ": " + value);
        }

        ImageIcon property = null;
        BufferedImage image = null;
        try {
            image = ImageIO.read(new File(imagePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
        property = new ImageIcon(image);

        value = property;
        __TABLE.put(imageName, value);

        return value;
    }

    protected ImageBundle(String suffix) {
        __fileSuffix = suffix;
    }

    public ImageBundle() {
        this("");
    }

    /**
     * @return
     * @uml.property  name="__KEYS"
     */
    public Enumeration<String> getKeys() {
        return __KEYS.elements();
    }

    protected final Object handleGetObject(String key) {
        return __loadImageFromJar(key);
    }
}

Usage:

ResourceBundle rsc = ResourceBundle.getBundle("ImageBundle"); //call rsc only once
...
ImageIcon icon = (ImageIcon) rsc.getObject("picture/plus.png");

If you are writing a game, you should use a game engine. Writing performant games is hard and brute force redrawings of everything on-screen is not going to cut it. Other smart people have already solved these problems and you can take advantage of their cumulated work rather than trying to reinvent the wheel.

I'm no expert on game engines, but the first hit on google for "java game engine" is jmonkeyengine.com . Maybe you should try it.

I had a performance issue with an interactive moving JComponent inside a Container, and found that calling repaint() on the parent , not on the moving component, gave a huge speed increase. I have no idea why - anybody know?

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