Click here to Skip to main content
15,885,244 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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:

------------------------------------------------------------------------------
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900