Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (516)
Games in Android Showcase (122)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Problem with image drawing and FPS  (Read 5365 times)
0 Members and 1 Guest are viewing this topic.
Offline sp0wner

Junior Newbie





« Posted 2012-08-22 17:11:32 »

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

while the code to load Images is the following:

Quote
Image image= ImageIO.read(new File(file));

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
Offline teletubo
« League of Dukes »

JGO Ninja


Medals: 48
Projects: 4
Exp: 8 years



« Reply #1 - Posted 2012-08-22 17:13:28 »

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

Offline sp0wner

Junior Newbie





« Reply #2 - Posted 2012-08-22 17:38:37 »

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

floorAl is an ArrayList<Tile>, 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.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline davedes
« Reply #3 - Posted 2012-08-22 18:04:30 »

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.

Offline 65K
« Reply #4 - Posted 2012-08-22 18:24:41 »

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.

Offline davedes
« Reply #5 - Posted 2012-08-22 18:33:38 »

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?

Offline 65K
« Reply #6 - Posted 2012-08-22 19:00:38 »

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.

Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #7 - Posted 2012-08-22 19:16:39 »

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?

- Jonas
Offline matheus23

JGO Kernel


Medals: 110
Projects: 3


You think about my Avatar right now!


« Reply #8 - Posted 2012-08-22 19:55:43 »

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.

See my:
    My development Blog:     | Or look at my RPG | Or simply my coding
http://matheusdev.tumblr.comRuins of Revenge  |      On Github
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #9 - Posted 2012-08-22 22:10:12 »

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.

100x100 tiles is nothing even for Java2D.

That being said we'd need to see the code.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline sp0wner

Junior Newbie





« Reply #10 - Posted 2012-08-22 23:01:01 »

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 Smiley
Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #11 - Posted 2012-08-22 23:20:56 »

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.
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.

- Jonas
Offline sp0wner

Junior Newbie





« Reply #12 - Posted 2012-08-23 02:33:51 »

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.
Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #13 - Posted 2012-08-23 02:54:27 »

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.

- Jonas
Offline sp0wner

Junior Newbie





« Reply #14 - Posted 2012-08-23 03:09:29 »

@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.
Offline StumpyStrust
« Reply #15 - Posted 2012-08-23 05:30:34 »

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.

1  
2  
3  
4  
5  
6  
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);

Offline 65K
« Reply #16 - Posted 2012-08-23 06:04:56 »

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.

Offline davedes
« Reply #17 - Posted 2012-08-23 06:43:27 »

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.

100x100 tiles is nothing even for Java2D.
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.

Offline Damocles
« Reply #18 - Posted 2012-08-23 07:21:24 »

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.

Offline StumpyStrust
« Reply #19 - Posted 2012-08-23 17:26:51 »

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. 

Offline matheus23

JGO Kernel


Medals: 110
Projects: 3


You think about my Avatar right now!


« Reply #20 - Posted 2012-08-26 18:03:26 »

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.
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.

Hmmm...
Yes. The only difference between your method and mine is the constructor stuff, and removing the lookup from the render method.

And I don't know how long a lookup in HashMap takes. I'm really not sure, but I'm sure a field "lookup" is much faster. And since rendering methods are called very very often, I thought that could be a huge difference... But I'm just checking how long a HashMap lookup would take... (I am also pretty sure that HashMap lookup time is dependent on the number of entrys. So it would take much longer if you'd have tons of sprites... and that'd be bad...).

Could be possible that would fall into the "premature optimization" bag...

See my:
    My development Blog:     | Or look at my RPG | Or simply my coding
http://matheusdev.tumblr.comRuins of Revenge  |      On Github
Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #21 - Posted 2012-08-26 18:23:47 »

Hmmm...
Yes. The only difference between your method and mine is the constructor stuff, and removing the lookup from the render method.

And I don't know how long a lookup in HashMap takes. I'm really not sure, but I'm sure a field "lookup" is much faster. And since rendering methods are called very very often, I thought that could be a huge difference... But I'm just checking how long a HashMap lookup would take... (I am also pretty sure that HashMap lookup time is dependent on the number of entrys. So it would take much longer if you'd have tons of sprites... and that'd be bad...).

Could be possible that would fall into the "premature optimization" bag...
The more I think about it, the more I know you're right Smiley
I'd hate to find out now that my teachers are full of it, and that HashMaps aren't instantaneous.

- Jonas
Offline Ultroman

JGO Knight


Medals: 25
Projects: 1


Snappin' at snizzes since '83


« Reply #22 - Posted 2012-08-26 18:36:18 »

I'd hate to find out now that my teachers are full of it, and that HashMaps aren't instantaneous.
Well, seems they're halfway right...or something. This is a very interesting read on performance of lists, sets and maps.

- Jonas
Offline jonjava
« Reply #23 - Posted 2012-08-26 19:48:57 »

I know this problem very well. You should not draw all the tiles simultaneously, only the ones that are visible. This way you can easily get around 1k visible tiles without much fps drop with simple java2d. At least I don't get any FPS drop while filling the screen with pink 1px height tiles on my netbook in this applet: http://jonjavaweb.orgfree.com/TestApplet.html (press W to insert pink tiles).

If you minimize the window where the applet is and maximize it again you get a glimpse of how and how fast the tiles are drawn on the screen. There should be around 50+ tiles per platform that are fit inside the screen + a few more extra to make sure you don't get undrawn tiles when moving the screen. So adding 20 pink tiles to each visible pillar/tile coordinate you should get around 20*50=1k tiles.

Then again why you'd need that many 1 pixel height tiles ontop of each other is very rare and performace shouldn't be an issue if you stick to minimum of 8px height tiles, even on larger screen sizes.

here's a post discussing a bit more in depth on how to draw only the visible tiles instead of ALL the tiles in the map: http://www.java-gaming.org/topics/drawing-isometric-tiles-inside-a-screen/24922/msg/212780/view.html

[EDIT]: Also, make sure you don't load a seperate bufferedImage for every single tile in your game. Similar tiles should share the same bufferedImage. Take a look at this post for more info: http://www.java-gaming.org/topics/loading-multiple-images/24878/msg/212071/view.html

Offline Quadro

Senior Newbie





« Reply #24 - Posted 2012-09-06 01:34:28 »

1) dont draw textures on tiles you can't see, probably the biggest thing here

2) don't overide the paint method(I'm assuming you're doing that, if not disregard this), run your painting in a thread, the performance increase is noticeable, on my machine cpu usage goes from 60 to 20

3)  don't use a lot of transparent images

4) limit your framerate, it can mean the difference from your game using 20 cpu or 5, a human can't tell the difference from 100fps and 800fps

also check your code for slowdowns, I always monitor the FPS on games I'm making so the moment I do something where the frames jump from from somwhere over 1000 to 40 I can find what is causing it
Offline JESTERRRRRR
« Reply #25 - Posted 2012-09-06 03:58:05 »

I seem to remember having this problem, and solving it with Volatile images and bufferstrategy
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

TehJavaDev (31 views)
2014-10-27 03:28:38

TehJavaDev (26 views)
2014-10-27 03:27:51

DarkCart (40 views)
2014-10-26 19:37:11

Luminem (21 views)
2014-10-26 10:17:50

Luminem (26 views)
2014-10-26 10:14:04

theagentd (32 views)
2014-10-25 15:46:29

Longarmx (61 views)
2014-10-17 03:59:02

Norakomi (57 views)
2014-10-16 15:22:06

Norakomi (46 views)
2014-10-16 15:20:20

lcass (43 views)
2014-10-15 16:18:58
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!