1

Java2D Game Running 20-30 FPS

I am writing a java2D game that as of now has an almost perfect memory footprint running only at around 2% of about a 4GB usable RAM space. The problem is the game only is running at around 20-30 fps just from rendering the character and the surrounding environment. I read already something about utilizing the GraphicsConfiguration, but when I tried that my fps soared right up to 120-130 fps while my memory increased to 70-80% and the frame was frozen in one place even if i moved the character. At this point I am stuck. I assume it has something to do with how many times i call g2d.fillRect() because after removing an area that's being referenced the game seems to speed up. The game seems to run smoothly at 20-30 fps, but I need to fix this otherwise my viewable gameobject painter loop will reduce my game to nothing but lag.

Rendering Method With Clipping Areas

private void renderEnvironment(Graphics2D g2d){

    for(int paint_index = 0; paint_index < paint_textures.size(); paint_index++){



        TexturePaint current_paint = paint_textures.get(paint_index);
        //Area a = new Area(new Rectangle(0, 0, host_frame.getWidth(), host_frame.getHeight()));
        //a.intersect(new Area(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint))));
        g2d.setPaint(new TexturePaint(current_paint.getImage(), new Rectangle(CamX, CamY, current_paint.getImage().getWidth(), current_paint.getImage().getHeight())));
        g2d.setClip(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint)));
        //g2d.fill(a);

        g2d.fillRect(0, 0, host_frame.getWidth(), host_frame.getHeight());

    }

    for(int paint_index = 0; paint_index < animated_textures.size(); paint_index++){

        TextureAnimation current_paint = animated_textures.get(paint_index);
        //Area a = new Area(new Rectangle(0, 0, host_frame.getWidth(), host_frame.getHeight()));
        //a.intersect(new Area(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint))));
        g2d.setPaint(new TexturePaint(current_paint.animatedPaint().getImage(), new Rectangle(current_paint.animatedPaint().getAnchorRect().getBounds().x + CamX, current_paint.animatedPaint().getAnchorRect().getBounds().y + CamY, current_paint.animatedPaint().getImage().getWidth(), current_paint.animatedPaint().getImage().getHeight())));
        g2d.setClip(AffineTransform.getTranslateInstance(CamX, CamY).createTransformedShape(paint_regions.get(current_paint)));
        //map_graphics.fill(a);
        g2d.fillRect(0, 0, host_frame.getWidth(), host_frame.getHeight()); 

    }g2d.setClip(null);
    g2d.drawImage(character_sprite.spriteImage(), host_frame.getWidth() / 2, host_frame.getHeight() / 2, host_frame);

    for(int paint_index = 0; paint_index < global_textures.size(); paint_index++){

        TextureAnimation current_paint = global_textures.get(paint_index);
        g2d.setPaint(new TexturePaint(current_paint.animatedPaint().getImage(), new Rectangle(current_paint.animatedPaint().getAnchorRect().getBounds().x + CamX, current_paint.animatedPaint().getAnchorRect().getBounds().y + CamY, current_paint.animatedPaint().getImage().getWidth(), current_paint.animatedPaint().getImage().getHeight())));
        //g2d.setClip(new Rectangle(0, 0, host_frame.getWidth(), host_frame.getHeight()));

        g2d.fillRect(0, 0, host_frame.getWidth(), host_frame.getHeight());

    }

}

EDIT : TextureAnimation.java

public class TextureAnimation implements ActionListener {

private final Action behavior;
private final BufferedImage image;
private final Component host;

private TexturePaint paint;
private final Timer t;
private final boolean isGlobal;

public int x;
public int y;

public TextureAnimation(Action a, BufferedImage i, Component c, boolean global){

    isGlobal = global;
    behavior = a;
    image = i;
    host = c;

    paint = new TexturePaint(image, new Rectangle(0, 0, image.getWidth(), image.getHeight()));

    t = new Timer(300, this);
    t.setInitialDelay(0);


}

public void playAnimation(){

    t.start();

}

public Boolean isGlobal(){

   return isGlobal; 

}

public void delayAnimation(int ms_delay){

    t.setInitialDelay(ms_delay);
    t.restart();

}

public void setIntervalDelay(int ms_delay){

    t.setDelay(ms_delay);

}

public void setTilePosition(int x, int y){

    paint = new TexturePaint(image, new Rectangle(Gscale.setX(x), Gscale.setY(y), Gscale.setWidth(image.getWidth()), Gscale.setHeight(image.getHeight())));

}

public TexturePaint animatedPaint(){

    return paint;

}

@Override
public void actionPerformed(ActionEvent e) {

    behavior.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
    //host.repaint(0,0, host.getWidth(), host.getHeight());
}

}

Researched Link

Java2D Performance Issues

Note : The Graphic2D parameter is taking on the graphics of the JPanel itself. So shouldn't java already create a Compatible image for me?

Community
  • 1
  • 1
StoneAgeCoder
  • 923
  • 1
  • 7
  • 13
  • 1
    Hmm, it's a small tip (so not really worthy of an answer) but I'd eliminate as many 'new's as you can in the render function as there is a very small overhead associated with creating new objects. Create some common Rectangles and TexturePaints during initialization and set their values instead. It's not likely to have a huge effect but it's a general rule that's helped me. – DFreeman Apr 02 '14 at 08:02
  • 1
    Some of the possibly relevant code is not provided. What is `TextureAnimation`, for exampl? It might (!) be that you have just found a tremendously inefficient way to paint images: Why are you using a `TexturePaint` and `fillRect`, and not just draw the images with `drawImage`? Also, what are the "clip" shapes that you are setting? – Marco13 Apr 02 '14 at 08:28
  • @Marxo13 Oh sorry about that I forgot to add my custom TextureAnimation Class. Also, BufferedImages are expensive in memory with the maps sizes I have so i had to switch to areas. My game begins with the creation of a small world by drawing to different areas using three different sizes of serialized shapes to draw to an assortment of areas which are matched with their corresponding texturepaint and texture animations. Therefore, I am able to set the affinetransformed clipping area and set its paint by interating through three different types of areas. I will edit my question above. – StoneAgeCoder Apr 02 '14 at 14:59
  • Well, I did not understand that last comment (and hoping that it does not sound arrogant: that's not a good sign). How can the memory consumption of BufferedImages be an argument, and at the same time, you are using a TexturePaint (that internally stores the BufferedImage)? – Marco13 Apr 02 '14 at 15:11
  • @Marco13 Map size is 10000px by 10000px. I could not at all draw bufferedimages to the screen that are that big because the RAM has to reference a file of that size. So I had to switch to using an area and to reference the bufferedImages from the texturepaints in order to reduce the amount of memory drawn from drawing a gigantic bufferedimage. – StoneAgeCoder Apr 02 '14 at 15:53
  • Sorry, I (and obviously others) don't understand what you are talking about. Maybe an http://stackoverflow.com/help/mcve could help. It seems that whatever you are doing with the `TexturePaint` there could similarly be done with a `BufferedImage`. The map size itself is unrelated to the size of the tiles. You don't need a reference to a BufferedImage that has 10000x10000px, you only need references to the *tiles* (which are most likely much smaller). – Marco13 Apr 02 '14 at 16:25
  • @Marco13 Sorry I was not able to explain it good enough. It is quite hard to without just sending you my whole application which has multiple different classes. I am really not sure how tiling works. I heard about this method and looked into it a little bit, but i don't know how easy it would be to do my map creation by painting using tiling. I could email you the jar itself if you want to take a look at the game itself? Can I do that? – StoneAgeCoder Apr 02 '14 at 16:36
  • So far, my statements have been based on assumptions: I simply don't see why you are using TexturePaint, and assume that you could just draw the tiles instead. I'm not sure about the policy concerning mail addresses here, and additionally, I don't want to feel "obliged" to answer. Isn't it possible to strip the program down to a single file that contains some minimalistic boilerplate code around your `renderEnvironment` method? – Marco13 Apr 02 '14 at 17:13
  • @Marco13 In order for you to really know why i am using this method instead of tiling you would have to see the game. The game is set up based on states much like what slick2D uses. At one portion of the game I draw circles of texturepaint to draw the world on the small scale canvas while at the same time creating those circles scaled up into the specified areas. I then use those areas to set the clip for the main world which you enter into after drawing the world, but it is a scaled up version of the one created. TextureAnimations is just Texturepaint that moves around using AbstractActions. – StoneAgeCoder Apr 02 '14 at 17:43
  • In my game i have ocean in the world for instance. Ocean in reality has tides so i created an external abstract action class that is passed into the TextureAnimation constructor as seen above. From there i am able to set the position which the texturepaint is on the screen giving it the effect of rising and lowering tide. – StoneAgeCoder Apr 02 '14 at 17:46
  • Sorry, all this sounds far too complex to easily point out where the performance is actually lost. The TexturePaint itself as well as the "scaling" that you mentioned several times are possible reasons. You may consider a profiler. When you send a mail to the address below, I'll possibly have a look at it, but can **NOT** promise anything. – Marco13 Apr 02 '14 at 18:09
  • @Marco13 I think you may have copied the wrong address idk how to send to that. – StoneAgeCoder Apr 02 '14 at 18:16
  • @Marco13 delete the comment I am having trouble running the jar from the command line hang on. – StoneAgeCoder Apr 02 '14 at 18:27
  • In any case, I don't need a runnable JAR, of course, but preferably a complete (Eclipse) project that I can just import and run. – Marco13 Apr 02 '14 at 18:41
  • Taking way to long to add the attachment its alright ill figure something out. – StoneAgeCoder Apr 02 '14 at 19:24

0 Answers0