User 13204940 Ответов: 0

Jpanel самый эффективный метод рендеринга


Привет,

Я создаю игру на Java и моя JPanel вызывает repaint() на себе каждый раз в то время как цикл. Некоторые графики статичны, а некоторые анимированы, поэтому мне трудно понять, как избежать рендеринга вещей каждый раз, когда они не нуждаются в повторном рендеринге.

Игровой цикл:
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++;
}

Кое-что я обнаружил, что paintComponent() по - видимому, вызывается асинхронно, потому что если я поставлю frames_this_second++; внутри цикла while он давал значения в миллионах. Однако то, как это происходит сейчас, дает значение около 1500, что вполне разумно, учитывая графические возможности моего компьютера и низкое влияние этого приложения на производительность, поэтому я считаю, что это правильно.

Однако, учитывая асинхронную природу, я считаю, что то, как я сейчас работаю, означает, что цикл while вызывает repaint() быстрее, чем paintComponent() на самом деле его вызывают, что может быть ужасно неэффективно, но не показывает никаких симптомов.

Игровой ландшафт состоит из блоков, каждый из которых хранится как отдельный объект, поскольку каждый материал имеет разное поведение. Некоторые из них статичны, а некоторые анимированы. А вот и анимированный:

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

Таким образом, вы можете видеть, что render() метод довольно эффективен, просто рисуя небольшое изображение, которое уже было считано из файла, используя класс загрузки графики, который хранит каждое изображение в отдельном файле. HashMap<String, Image>.

Итак, помимо нескольких вещей, в которых я не уверен, дилемма заключается в следующем;

Система автоматически вызывает paintComponent(), Я предполагаю, чтобы визуализировать все, когда, например, изменяется состояние окна. Мой игровой цикл также должен рендерить вещи как можно быстрее, чтобы дать как можно более высокую частоту кадров, с которой может справиться система. Таким образом, игровой цикл заканчивается вызовом paintComponent(), а также система, делающая это автоматически. Однако, когда я вызываю его в игровом цикле, я могу сделать некоторые оптимизации, такие как не перерисовывать статические материалы. Но когда система вызывает его, она должна отрисовывать все. Так или иначе, мне нужно найти способ рассказать об этом. paintComponent() то ли рендерить все подряд, то ли просто анимировать объекты. Я не могу использовать простое логическое значение в глобальной области видимости, потому что paintComponent() асинхронный. Это будет выглядеть примерно так:

private boolean render_static = false;

while(true)
{
	render_static = true;
	repaint();
	render_static = false;
}


Есть ли какой-то способ достичь того, что я ищу, или это вообще неправильный подход?

Что я уже пробовал:

------------------------------------------------------------------------------

0 Ответов