Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (481)
Games in Android Showcase (110)
games submitted by our members
Games in WIP (548)
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  
  2D Game - Problems with Images (Memory & CPU)  (Read 5020 times)
0 Members and 1 Guest are viewing this topic.
Offline Schnagga

Junior Newbie





« Posted 2007-12-12 16:45:13 »

Hello guys,

we are programming our first 2D Java game and are very inecperienced in the topic performance tuning. We are not sure why the performance is so bad (probably there are too many reasons), but it's mainly about the Image Drawing. Before we used Images (png and jpg for the background) the performance was great and the game has run fast. About the game: It's a 2d space shooter like space invaders.
Because we are quite sure that the images cause the problems the following codes are limited to the drawing methods...

Loading of the Images (example class Shot):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
public class Shot extends Elements {
    private BufferedImage[] shot = new BufferedImage[3];
    String shotName;
    File shotSound;
   
    public Shot(...) {

        File shotAnimation[] = new File[3];
       
        switch (mode) {
            case 0: shotName = "defaultshot"; width = 5; height = 5; break;
            ...
        }
       
        for(int i = 0; i < shotAnimation.length; i++) {
            shotAnimation[i] = new File (shotName + i + ".png");
        }
       
        try {
            for(int i = 0; i < shot.length; i++) {
                shot[i] = ImageIO.read(shotAnimation[i]);

            }
        }        
        catch (IOException e) {}
    }
   
// ...
   
    public void paintComponent(Graphics g) {
    if(getAlive() == true && counter < 3) {
            g.drawRect(getXc(), getYc(), width, height); // for collision, nothing to do with the images / problems
           g.drawImage(shot[counter], getXc(), getYc(), null);
            delay++;
            if(delay %15 == 0)
                counter++;
            if(counter == 3)
                counter = 0;
       }      
    }


We thought about loading all Images in another class and use them in the classes (shot, spaceship and so on...). Maybe this would be a performance push? We are not quite sure.

The class, whrere the paintComponent() is used (Level):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
public void paintComponent(Graphics g) {
    background.paintComponent(g);
        spaceship.paintComponent(g);
        boss.paintComponent(g);
       
        for(int i = 0; i < shots.size(); i++) {
            if(shots.get(i).getAlive() == true)
                shots.get(i).paintComponent(g);
        }

//...
   }


We are using Arraylists. Maybe this is slowing down the Performance? But we thought its better to use dynamic arraylists than the static Arrays.

The main Problem could be the Main class:

1  
2  
3  
4  
5  
6  
ActionListener Update = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                repaint();
            }
        };
        new javax.swing.Timer(10, Update).start();


We have to repaint the whole panel after a few milliseconds, because otherwise the frame or the panel doesnt update and we aren't able to see the differences (moving ship, enemies, generates shots and so on). Everything is still and only updates, if the frame is minimized and again on the desktop.

Maybe there are another solutions for updating the frame / panel or loading the images (faster ones of course  Grin ). So it would be great, if anyone out there could help us, but thanks for taking the time reading all this anyway. Of course we would be grateful for hints on the net, but the whole possibilities in using 2D and Images some kind of overwhelmed us, that's why we decided to post something here.
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #1 - Posted 2007-12-12 17:18:53 »

a) Use a profiler (-Xprof will be good enough usually)
b) javax.swing.Timer is a rather bad timing method (well, for games that is)

How big (dimensions - not file size) are the images and are you using translucent PNGs?

弾幕 ☆ @mahonnaiseblog
Offline Schnagga

Junior Newbie





« Reply #2 - Posted 2007-12-12 21:00:47 »

I tried it with -Xprof, but it doesn't work properly. I get a few infos, but I couldn't really start the game witht the start button ( like I usually do). I only get a empty window. Then I tried -Xrunhprof but there I get a huge .txt File.

Xprof gives me the following output:
Quote
Flat profile of 0.21 secs (18 total ticks): main

  Interpreted + native   Method                       
 13.3%     0  +     2    sun.awt.Win32GraphicsEnvironment.initDisplay
 13.3%     0  +     2    java.util.zip.Inflater.inflateBytes
  6.7%     0  +     1    java.io.FileInputStream.open
  6.7%     0  +     1    java.io.WinNTFileSystem.canonicalizeWithPrefix0
  6.7%     0  +     1    java.io.FileInputStream.readBytes
  6.7%     0  +     1    sun.awt.windows.WDesktopProperties.init
  6.7%     0  +     1    sun.java2d.loops.GraphicsPrimitiveMgr.registerNativeLoops
  6.7%     1  +     0    java.awt.image.DataBufferByte.<init>
  6.7%     1  +     0    java.awt.image.ColorModel.getLinearRGB16TosRGB8LUT
  6.7%     1  +     0    java.util.zip.InflaterInputStream.read
  6.7%     1  +     0    java.lang.String.toLowerCase
 86.7%     4  +     9    Total interpreted

     Compiled + native   Method                       
  6.7%     1  +     0    com.sun.imageio.plugins.png.PNGImageReader.decodePaethFilter
  6.7%     1  +     0    Total compiled

         Stub + native   Method                       
  6.7%     0  +     1    java.lang.StrictMath.pow
  6.7%     0  +     1    Total stub

  Thread-local ticks:
 16.7%     3             Blocked (of total)


Flat profile of 6.45 secs (4 total ticks): Image Fetcher 0

  Interpreted + native   Method                       
100.0%     1  +     0    sun.awt.image.PNGImageDecoder.produceImage
100.0%     1  +     0    Total interpreted

  Thread-local ticks:
 75.0%     3             Blocked (of total)

I changed the timer to a java.util.Timer, but this wasn't that successful. I would say it was better with the javax.swing.Timer...

The dimensions are totally different.. a shot is about 5x10 and the background, or the level (scrolling down so it looks like the ship is moving) is really big... about 1200x600. The game is in 800x600. But we used the lowest quality for the background (jpg. photoshop 0) so it has a file size of 40 kb. At first we used a good looking background but it totally decreased the performance. The pngs (shots, enemies...) are made with photoshop. I don't know if they are made translucent. I will ask tomorrow. The only thing I know is, that they are made without background (no black or white), otherwise we would have a white outline / contour and the enemies, ships (.. and so on) wouldn't look like they are in the level. (I hope it was understandable Cheesy).
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline oNyx

JGO Coder


Medals: 2


pixels! :x


« Reply #3 - Posted 2007-12-12 21:44:04 »

>I changed the timer to a java.util.Timer, but this wasn't that successful. I would say it was better with the
>javax.swing.Timer...

Either use System.nanoTime (Java 1.5+) or System.currentTimeMillis.

>But we used the lowest quality for the background (jpg. photoshop 0) so it has a file size of 40 kb.

File size doesn't matter. It gets decompressed... so a 1200x600 jpg will take 2160000 bytes.

I just skimmed over the code... you're using components for everything? Use a Canvas (with BufferStrategy) and draw the images directly into that one.

Also:
1  
for(int i = 0; i < shots.size(); i++)

It's faster if you do it backwards:
1  
for(int i = shots.size()-1; i >= 0; --i)


1  
if(shots.get(i).getAlive() == true)

"==true" can be omitted. Also at the drawing stage there should be only bullets in that list, which are "alive". You also check if it's alive in the drawing method itself... why?

And uhm... each time a Shot is created you load the images? I hope you aren't doing that over and over... well, I can't tell from those snippets.

弾幕 ☆ @mahonnaiseblog
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #4 - Posted 2007-12-13 18:21:33 »

Hello guys,

we are programming our first 2D Java game and are very inecperienced in the topic performance tuning. We are not sure why the performance is so bad (probably there are too many reasons), but it's mainly about the Image Drawing. Before we used Images (png and jpg for the background) the performance was great and the game has run fast. About the game: It's a 2d space shooter like space invaders.
Because we are quite sure that the images cause the problems the following codes are limited to the drawing methods...

So what images are you using now?

Could you run your application with -Dsun.java2d.trace=log and see what is
printed when your images are rendered?

There was a bug which prevented images loaded with ImageIO from
being cached in vram The workaround was to copy
those images into another image that you create yourself
(say with createCompatibleImage(w,h,Transparency) where
transparency is the same transparency as the one in
the image you loaded).

Which java version are you running this on?
If your images are translucent then they won't be accelerated
unless you're using one of the non-default rendering
pipelines (either opengl or d3d). They will be accelerated
if they are opaque or 1-bit transparent.

Thanks,
  Dmitri
Java2D team
Offline Schnagga

Junior Newbie





« Reply #5 - Posted 2007-12-13 22:10:40 »

First of all: Thank you very much! It’s great to get so many responses in 24 hours. I really appreciate that and I’m happy about finding this forum.
I tried today to use the System.nanoTime and System.currenTimeMillis but obviously I’m too stupid to build a timer with it. I searched this forum and google, but I haven’t found a good instruction for it. If I use a Thread for it, nothing would be won, am I right? So can you please tell me how I build a timer with them?
The file size doesn’t matter? I believe you, but maybe you can explain to me why the whole game was lagging and shaking, when we used the high quality backgrounds? Then we decided to use a low quality background and it run a lot more fluid.
Then I tried using BufferStrategy, but I must have done something wrong. At first I used the tutorial I found at: http://gpwiki.org/index.php/Java:Tutorials:Double_Buffering
At first everything looked fine:

And then it destroyed the status panel I used:

The score and defeated enemies are blinking when they get updated for a really short moment they are displayed on the screen. Then I tried to change the level  Jpanel into a Level Canvas and tried to add it with: frame.getContentPane().add(canvas);

But then I get a grey background. Then I tried to change the paintComponent() method in paint() methods, but then I get nullpointerexception about graphics g. Sad It’s crazy… maybe it’s not necessary? Or is it that good for the performance? I have read that it’s not good to use canvas with swing?
The thing with double checking… there is no reason for doing it… only stupidity. Fixed it! Cheesy
At the moment I’m loading the image each time a shot is created. We thought about that ourselves and tried to change it. Do you know a good way to do it? Maybe a ImageLibrary class? In which all images are loaded and then you give in the level paintComponent() method:
public void paintComponent(Graphics G, BufferedImage spaceship)
Is this a good way? I started to build this class, but now I’m too tired and can’t concentrate any more. I will do it like that tomorrow and maybe it runs faster with it.

At the moment we are using BufferedImages. I read that I should use VolatileImages? But then I read, that the BufferedImages are way better in the actual versions?!?
Or do you mean the photoshop output? Cheesy That are mainly pngs, just the background is a jpg. I have run the application with -Dsun.java2d.trace=log and the output was:

Quote
sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer RGB DirectDraw")
sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)s
un.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer RGB DirectDraw")
sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)s
un.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer RGB DirectDraw")
sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer RGB DirectDraw")
sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer RGB DirectDraw")
sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb) sun.java2d.loops.DrawGlyphListAA::DrawGlyphListAA(AnyColor, SrcNoEa, IntRgb)


But I don’t unterstand it. Cheesy I will try the createCompatibleImage() tomorrow… if it’s a better way to handle the images. And  I will look how I can make them opaque. Then I let the method run with
-Dsun.java2d.opengl=True
On my main computer the cpu usage was lower  then, but on my laptop the content of the window didn’t load… Sad
Oh… and we are running Java on 1.6.
Again: Thank you very much. It’s really fun to make a game, although we are totally beginners. Maybe sometimes it will run as fast as it should… Cheesy
Offline trembovetski

Senior Member




If only I knew what I'm talking about!


« Reply #6 - Posted 2007-12-14 17:47:39 »

For this type of game you are probably better of not using Swing but use
"active rendering" (search for it on this forum and google, there's a few
articles on this, including http://ping.dev.java.net).

Active rendering would typically include using BufferStrategy for
double-buffering, and having your own rendering loop. That way
you could get much more consistent frame rate.

You probably don't need to use VolatileImages since BufferStrategy
is a better double-buffering mechanism. For the sprites BufferedImages
should be fine.

Judging by the trace output you have a bunch of translucent images.
Make sure that only images which need to be translucent
are translucent, the rest may be opaque or bitmask (1-bit transparent).
You can typically chose when exporting your artwork from
your graphics editor.

As I mentioned, translucent images aren't hardware accelerated
by the default pipeline. The opengl pipeline works well if your
drivers are good. You can also try the D3D pipeline (in 1.6 set
-Dsun.java2d.d3d=true, in 6u10 which you can get from
jdk6.dev.java.net it is enabled by default).

Thanks,
  Dmitri
Java2D Team
Offline ddyer

Senior Member


Medals: 5



« Reply #7 - Posted 2007-12-14 23:36:50 »

You should have a look around my web site, boardspace.net.  All the games there use composited, partially
transparent  images as their basic design element.   The games are drawn on a plain canvas using drawImage.
Multiple java components, Swing, and toolkit based buffering strategies are not invoved.

In general:

the "paint" method should not paint.  It should just set a flag saying some painting is required, actual painting should be
done on your clock cycle.  This is a good strategy both because "paint" messages are erratic, and you don't want your
painter running through data structures which are being mutated by responses to network or mouse events.

use 2 or three levels of "full size" bitmaps, starting with a fixed background bitmap, ending with ephemera like bullets in transit.
Draw from back bitmap to intermediate, add moving elements to the intermediate, then draw the intermediate to the completed
bitmap the real window.

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 781
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #8 - Posted 2007-12-16 15:31:00 »

According to your first post, every time you create a new Shot object, you read images from files and decom,press them into buffered-images.

Just keep the images around, reuse them. You'll see a MASSIVE performance boost.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Jackal von ÖRF

Junior Member





« Reply #9 - Posted 2007-12-16 17:27:41 »

What Riven just said might also explain the improvement in speed when you compressed the background image smaller - less file IO is needed to read smaller files, so it might be faster to load the image, even though the time needed to draw the image on screen does not depend on the compression (since the image is stored uncompressed in the memory). You could for example build some kind of a image cache which reads the images only once, when they are first requested from the cache, and on subsequent requests it returns the same image instance. That way no time is wasted in reading the file from disk and in decompressing the image more than once.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #10 - Posted 2008-02-08 05:53:23 »

Did you call bufferStrategy.show()? If you don't do this, your images will sort of draw, but will be choppy and messed up. Make sure to call that.

See my work:
OTC Software
Offline JAW

Senior Member


Medals: 2



« Reply #11 - Posted 2008-05-09 12:48:26 »

Just something general:
Using compatible BufferedImages often can improve performance. There are createCompatibleXXX methods around somehwere in the GraphicsConfiguration or so. I dont know what type of Image you get from ImageIO.

And second, no transparency is fastest, bitmask transparency is almost as fast, but full alpha is costly. PNG supports full alpha, and maybe even without having transparent areas, they are treatet that way?

I would try to create a compatible bitmask transparency image for your sprites.

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

atombrot (26 views)
2014-08-19 09:29:53

Tekkerue (24 views)
2014-08-16 06:45:27

Tekkerue (23 views)
2014-08-16 06:22:17

Tekkerue (14 views)
2014-08-16 06:20:21

Tekkerue (22 views)
2014-08-16 06:12:11

Rayexar (60 views)
2014-08-11 02:49:23

BurntPizza (38 views)
2014-08-09 21:09:32

BurntPizza (30 views)
2014-08-08 02:01:56

Norakomi (37 views)
2014-08-06 19:49:38

BurntPizza (67 views)
2014-08-03 02:57:17
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

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!