Problem with image drawing and FPS

I am developing a full screen exclusive mode isometric tile game from scratch -i.e. I don’t use a game engine- and I have a problem when it comes to drawing “BufferedImages” and “Images” on screen. (I am using active rendering)

The default FPS value is set to 80, but when the map tiles are drawn on screen the FPS value drops at 60. The map size (=array’s size) at the moment is 100 tiles (10 width * 10 height). If I change that to 100*100=1000 tiles then the FPS value drops to 0 and the game cannot be played.

The code I use to load buffered images is the following:

[quote]BufferedImage image= ImageIO.read(new File(file));
[/quote]
while the code to load Images is the following:

[quote]Image image= ImageIO.read(new File(file));
[/quote]
where file is a string containing the path to the image.
The size of the tile-image that it loaded is ~3KB.

Do you have any idea why does the FPS value drop? Or a different way to suggest on how to draw images without occuring problems to the FPS value?

Thanks in advance,
sp0wner

You should provide the code you’re using to draw your images if you want to know what is wrong with it.

There are many draw functions used in the game, so here I am posting the one I think is the most responsible one.
The code to draw the “floor” of the map is the following:

[quote] public void draw(Graphics g){
Graphics2D g2d = (Graphics2D) g;

	//draw Floor
	for (int i = 0; i < floorAl.size(); i++){
		g2d.drawImage(floorAl.get(i).getImage(), null, floorAl.get(i).getX(), floorAl.get(i).getY());
	}
}

[/quote]
floorAl is an ArrayList, where all the Tile objects representing the floor are contained along with the their x,y positions and their BufferedImages.
The Tile class makes use of another class called BufferedImageLoader which is responsible for loading any BufferedImage passed as a parameter to the constructor.

Java2D is slow; you will probably not be able to achieve (reliable) full-screen performance using active rendering (i.e. clearing the screen every frame).

Instead I would suggest LibGDX, Slick2D, RabbitEngine, or straight LWJGL.

e.g. Rendering a full-screen tiled map (32x32 tiles) on my iMac (3.06 GHz Intel Core 2 Duo; NVIDIA GeForce 9400) leads to ~25 FPS at 1920x1080. The same runs at ~150 FPS using Slick.

Impossible to spot without the complete source. Maybe incompatible image formats. Use a profiler.
In any case, 10x10 tiles is really nothing.
I got a frame rate of 1400 when drawing 16x12=192 tiles using volatile images and Java2d.

The OP says the problem occurs with 100x100 tiles. By today’s standards that isn’t much, but it’s too much for Java2D’s standards.

I’d love to see a self-contained example using volatile images. Could you post some code?

Okay, I just took the written 1000 tiles, not 10000. Which sums up to a lot for 60fps indeed.
I would use bigger tiles in any case…
I don’t have an extractable example, but you have to take care to create compatible images, not to mess with pixels and get images unmanaged.

You really shouldn’t keep BufferedImages in your Tiles, but rather a String-identifier. Then have a HashMap of BufferedImages with a String as key, so you can do something like:
g2d.drawImage(imageMap.get(floorAl.get(i).getImageString()), null, floorAl.get(i).getX(), floorAl.get(i).getY());

I don’t know if that’ll help your FPS, though. Can you post your Tile-class in the pastebin and provide a link?
Are you making sure that the images you load are compatible with the graphicscontext?

Or even better:

have something like a “manager”-class managing all the Images (so for example “ImageManager”).

Then the ImageManager holds a hash-map of all the Images you have in your res/ folder (or whatever), and then puts them into a HashMap<String, BufferedImage>.
The String (the Key), will have the name of the Image loaded (for example “grass.png” / “dirt.png” / “characters/mike.png” or whatever).

Then in the constructor of the Tile you ask the ImageManager for a reference of the Image, called (for example) “grass.png”, and save it in a member field.

Tl;Dr:
same as Ultroman, but you won’t need to “load” the BufferedImage from the HashMap everytime you want to draw it, which is bad (or slow), because it needs to “search” through the map with an algorithm. The more Images you have, the longer it will take to get it from the HashMap.
Just take a reference to the Image, which is then actually stored in another class and only loaded once.

100x100 tiles is nothing even for Java2D.

That being said we’d need to see the code.

Below you can see the classes of the program. I made a small version of my game that runs in windowed mode (the same problem with fps dropping occurs in both full screen mode and NON full screen mode) which only paints the background and contains the classes that are needed to do that.

Game class:
http://pastebin.com/eiH2BDwL

gamePanel class (Most of the gaming loop code is taken from a book i’ve been reading):
http://pastebin.com/TDYhBAfC

World class:
http://pastebin.com/uVaWZWZa

Floor class:
http://pastebin.com/8FScvJay

Tile class:
http://pastebin.com/xztK6qyj

Map class:
http://pastebin.com/2HBnxYEN

The image i use is this one (to change the location within the program change the string in the beginning of the Floor class: 40th line)
http://desmond.imageshack.us/Himg822/scaled.php?server=822&filename=cursor82.png&res=landing

[EDIT:]
You can change the map size by modifying the mHeight and mWidth variables at the very beginning of the World class.

I tried using volatileImages but didn’t speed up my FPS value.
An alternative of Java2D like slick2D is not an option right now. I’d like to find a way to solve my problem using java2D. In case I can’t find a solution, then I’ll use another library like slick2D, etc.

By the way thanks everyone for your answers :slight_smile:

What is the difference from your method to mine, except for the dedicated class? My suggestion was essentially the same: “have a HashMap of BufferedImages with a String as key”. I’ve done somewhat what you said for my game, and put my static HashMap of images in a ResourceHolder class, so I can access it from every class that has a reference to the ResourceHolder, like my Creator-class and my draw-method in the Game-class.

Do you mean you give the Tile-class a BufferedImage as a parameter in the constructor from the Tile-class? So you’re linking the image to the Tile-class instead of looking it up every update?

Just to clarify; this could come off as a whiney post, but I’d just love to know how much I can gain from changing to your proposed method compared to mine. I was under the impression HashMap lookups were pretty instantaneous.

I think I found a temporary solution to my problem, although any other ideas are more than welcomed. My solution is to load images as ImageIcons. I tried to load a 100x100 map at 80 fps/ups and the results were the game to run at 50 fps and 80 ups.

I’m checking, updating animations on, and drawing around 3-500 40x40px tiles at a steady 60fps, and this only takes up about a millisecond per frame/update. There must be something terribly wrong in your code. Are you sure you’re not reloading all images each draw or update or something?

I’d recommend doing some timing-debugging on the different parts of your gameloop, to figure out what is taking so much time. Time every event, like update(), draw() and whatever you have.

@Ultroman:
I’ll check what you said, maybe there is something I can’t think of right now.
The only thing that comes in mind is that I don’t draw a specific area of the map size on the board. I draw all 1000 tiles, even though those that are not supposed to be drawn. Is it possible that causing the issue? In other words I am NOT implementing something like this: http://user-generated-content.java-gaming.org/img-vault/d7729d02ad9f36f000dfbbec5d2a51d10d7bde17a12ded3b82ec52acbd79de60.png . Instead all of my tiles are drawn.

That could be it but even then 1k images should not be that slow. Make sure you are loading images by getting compatible images from the Graphics Environment. You can also specify whether you want transparency or not. Java2D does some software rendering which means that as you scale up screen size you don’t get fill rate limited.

Also, when it comes to storing images, there is nothing wrong with having a BufferedImage reference in a class. It is good to have a resource management system but keeping a reference is not bad either.

You should not deal with ImageIcons. You need to properly load everything.

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gs = ge.getDefaultScreenDevice();
    GraphicsConfiguration gc = gs.getDefaultConfiguration();

    // Create an image that does not support transparency
    BufferedImage bimage = gc.createCompatibleImage(100, 100, Transparency.OPAQUE);

So, of which number are we talking ?
100x100 = 10000*60 = 600000 tiles per second ?

Anyway, check your fps calculation.

Also, I would disable Swing’s repainting (setIgnoreRepaint) and not extend JPanel and not make it runnable.

Please provide some Java2D code that will perform 100 * 100 tiles (e.g. 32x32 pixels or smaller) at 60 FPS on the majority of systems within the past couple years.

Until then, no, 100x100 tiles is way too much to expect from Java2D.

If the rendering is too slow, use more memory,
eg: precalculate static tiles/backgrounds wich dont change.

If the rendered map image is too large, only rerender the part wich is visible + some border to enable a smooth scrolling.

The problem then is probably then the order of elements (eg dynamic elements must be obstructed by walls)
There is a range of solutions. (like a Z Buffer, or a partial rendering)
But basically, the floor-tiles can be drawn first anyway, as everything is ontop of them, they cannot obstruct anything.

I think that java2D does z culling under the hood. They create rectangles and wont draw the intersection of said rectangles.
The key here is draw calls. Problem with tile based systems is that if you have 1000 tiles that need to be drawn that is 1k draw calls. Cut down on draw calls as much as possible. All games I have made run fairly well at 1-2k draw calls. fillShape() drawImage() once you pass 5k, just about any system will drop fps like crazy. Size of image has virtually no impact on performance on most systems that have a DGPU.