Hi,
I'm creating a game in Java and my JPanel calls
repaint()
on itself every time in a while loop. Some graphics are static, and some are animated, so I'm having trouble figuring out how to avoid rendering things every time which don't need re-rendering.
Game loop:
private int frames_this_second = 0;
public void play()
{
Timer fps_timer = new Timer();
fps_timer.schedule(new TimerTask()
{
@Override
public void run()
{
fps_label.setText("FPS: " + frames_this_second);
frames_this_second = 0;
}
}, 1000, 1000);
while (true)
{
repaint();
}
}
@Override
public void paintComponent(Graphics g)
{
g.clearRect(0, 0, window.getWidth(), window.getHeight());
Main.get_game().screen_debug("paint");
for (IGameObject object : object_registry.get_objects())
{
object.render(g);
}
frames_this_second++;
}
Something I've discovered is that
paintComponent()
appears to be called asynchronously, because if I put
frames_this_second++;
inside the while loop, it gave values in the millions. However, the way it is now, gives a value of around 1,500 which is reasonable considering my PC's graphics capabilities and the low performance impact of this application, so I believe that to be correct.
However, considering the asynchronous nature, I believe the way I have it currently working means the while loop is calling
repaint()
faster than
paintComponent()
is actually being called, which may be horrendously inefficient but isn't showing any symptoms.
The game terrain is made up of blocks which are each stored as a separate object as each material has different behaviours. Some are static and some are animated. Here's the animated one:
public class AnimatedBlock extends ITerrainBlock
{
private List<Image> graphics;
private int graphic_index = 0;
public AnimatedBlock(int x, int y, List<Image> graphics)
{
super(x * Main.get_game().BLOCK_SIZE, y * Main.get_game().BLOCK_SIZE, true);
this.graphics = graphics;
}
@Override
public void render(Graphics g)
{
g.drawImage(graphics.get(graphic_index), x, y, Main.get_game().BLOCK_SIZE, Main.get_game().BLOCK_SIZE, null);
}
public void advance_animation_frame()
{
graphic_index = graphic_index == graphics.size() - 1 ? 0 : graphic_index + 1;
}
}
So you can see that the
render()
method is quite efficient, just drawing a small image which has already been read from the file using a graphics loading class, which stores each image in a
HashMap<String, Image>
.
So as well as the few things above which I'm not sure about, the dilemma is as follows;
The system automatically calls
paintComponent()
, I assume to render everything when for example the window state changes. My game loop also needs to render things as fast as possible to give as high a framerate as the system can handle. So the game loop ends up calling
paintComponent()
, as well as the system doing it automatically. However, when I call it in the game loop, I can make some optimisations such as not re-rendering static materials. But when the system calls it, it needs to render everything. Somehow I need to figure out a way to tell
paintComponent()
whether to render everything, or just animated objects. I can't use a simple boolean in the global scope because
paintComponent()
is asynchronous. Doing so would look like this:
private boolean render_static = false;
while(true)
{
render_static = true;
repaint();
render_static = false;
}
Is there any way to achieve what I'm looking for, or is this the wrong approach altogether?
What I have tried:
------------------------------------------------------------------------------