8
\$\begingroup\$

[Reposting this question from stackoverflow, as it was pointed out that it fits better here.]

I'm currently porting my 2D game engine to Java. I looked at some of the game libraries pointed at here on stackoverflow. However, the ones I looked at were rather simplistic and didn't even state if they supported things like alpha transparency, so I decided to port my C++ renderer for which I had already written out the logic.

This renderer is a pure software renderer which uses tiling to avoid needless re-rendering. I optimized its scrolling performance by creating an "offscreen buffer" a little larger than my output pane, and blitting this offscreen buffer onto my output on every frame. This way, I could avoid redrawing tiles needlessly just because I scrolled a pixel on the map.

I used Java's AWT to implement it, using a large BufferedImage for the offscreen buffer. The CPU usage is okay(around twice of what I had in C++), but there's an odd problem with continuous scrolling, where every second or so, the renderer will lag out for around 0.2 seconds.

Since there's nothing in my own code that would occur in these periods, and since the spikes disappear if I don't draw my offscreen buffer onto the main view, I can only conclude that Java is doing some internal optimization of its own. However, I'm not sure what it does, nor do I know which of my own optimizations I would have to remove to get rid of the spikes. Also, it might be that java AWT wasn't made with continuous, high FPS scrolling in mind, and that's entirely unusable for this purpose.

Is there some way for me to get rid of these spikes?

\$\endgroup\$
2
  • 4
    \$\begingroup\$ Could it be the garbage collector hitting you? \$\endgroup\$
    – bummzack
    Commented Aug 30, 2011 at 19:20
  • \$\begingroup\$ @bummzack: Possibly. In the profiler it looks like this: i.imgur.com/EMxkA.png However, I'm not sure how I would reduce this effect, especially if it's caused by my calls to graphics.drawImage \$\endgroup\$
    – cib
    Commented Aug 30, 2011 at 20:25

2 Answers 2

4
\$\begingroup\$

While I cannot be sure without looking at your code, it sounds like your problem is the garbage collector. In Java, you have major and minor garbage collections taking place every now and then. The minor use up some of your cpu but wont bug you too much. The major collections can be a real problem for real time apps such as games since they will actually pause everything while they are running.

There are two options to solve this. First you can tweak the JVM to make sure less major collections take place. Secondly (and recommended), you can make sure you do not leave too much garbage. Simply check where in your app you create a lot of objects(in my games those are usually the vector3 classes) and make sure you reuse them as much as possible (especially in inner loops etc).

\$\endgroup\$
2
\$\begingroup\$

Yes.

For 2D sprite-based games, AWT can be used to handle the rendering to great effect. It can even be hardware accelerated, depending on the available hardware.

Without any code or detailed profiling snippets, it's hard to say what the issue is. Best I can do is offer some basic tips for working with Java and AWT when building games.

Working with the Garbage Collector

The GC in Java is something that we have to really keep in mind as we are building our games. It will run periodically and look for objects that do not have any references to them, and remove them from memory. This removal process is slow and is likely the cause of the hitching you are experiencing.

My suggestion is to avoid creating object references that aren't going to be kept around for the lifetime of the execution (or at least, as much as possible). The ideal goal is to make sure the GC doesn't have anything to do whenever it runs.

In practice, you may end up with a lot of static variables that you reuse throughout the game. Here's is a very contrived example of how I tend to deal with that:

public final class Resources {
    public static Map<int, String> strings;
    public static Map<int, Texture> textures;
    public static Map<int, GameObject> objects;
    public static Map<int, SoundEffect> sounds;
}

During loading screens is where you can grow or shrink your Map instances using the new keyword. But during play, you'll want to avoid that as much as you can. If something is destroyed during play, set a flag on the object so you know it's not something that is currently active. If you need to spawn a new object, go through your Map until you find one that isn't active, and set it's properties and mark it as active.

This is something you'll want to keep in mind when using Java for performance-sensitive applications regardless if you are using AWT, JavaFX, or OpenGL to do the rendering.

Canvas

For AWT in particular, I would highly recommend using the Canvas class to render everything on to for various reasons:

  • You have better control of when things render. This means you can write your own game loop and do things like interpolation, extrapolation, rate-limiting, etc.
  • It seems to perform better. I was able to get more things on screen at once at an acceptable frame rate as opposed to trying to animate a bunch of Label and Image objects.
  • It's easier to embed in editors. Being able to setup a Frame with normal GUI controls and pointing your game's rendering logic to a Canvas meant I could re-use the game's rendering code in the editor tools.
  • It gives you easy access to the Java2D API (aka, the Graphics2D class).
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .