Сильное мерцание тройного буфера
Разве тройная буферизация и Canvas не должны быть оптимальным решением для пассивного рендеринга? Я только что написал этот код Java, который отображает круг. Если я оставлю буферную стратегию до 3, она так сильно мерцает. Если я уменьшу его до 2 или 1, все в порядке. Может я что то не так делаю?
public void run(){
while (running){
update();
draw();
}
}
public void update(){
}
public void draw(){
BufferStrategy bs = getBufferStrategy();
if (bs==null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillOval(30, 30, 20, 20);
g.dispose();
bs.show();
}
и это класс JFrame, где я положил холст
public class Game {
public static void main (String [] args){
Pan game = new Pan();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(game);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
}
2 ответа
Две вещи прыгают на меня.
- Ваш "цикл" работает без каких-либо задержек. Это означает, что экран будет обновляться столько раз, сколько возможно, это может быть слишком много для аппаратного обеспечения, чтобы не отставать. Вообще говоря, вы хотите стремиться к 25fps, это поможет создать иллюзию плавного движения
- Вы не готовите
Graphics
для рисования. Каждый раз, когда вы получаетеGraphics
контекст изBufferStrategy
вы на самом деле получаете последнее, что было использовано. Это означает, что все, что было нарисовано, все еще. Там вы должны очистить это. Мерцание (возможно) происходит от того факта, что один изGraphics
контексты уже заполнены цветом, а другие нет.
Ниже приведен очень простой пример, включающий немного анимации.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class DoubleBuffer {
public static void main(String[] args) {
Pan game = new Pan();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(game);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
public static class Pan extends Canvas implements Runnable {
private int xDelta = 2;
private int x = 0;
private int y = 20;
public Pan() {
}
public void start() {
new Thread(this).start();
}
public void run() {
while (true) {
update();
try {
Thread.sleep(40);
} catch (InterruptedException ex) {
}
draw();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void update() {
x += xDelta;
if (x + 20 > getWidth()) {
x = getWidth() - 20;
xDelta *= -1;
} else if (x < 0) {
x = 0;
xDelta *= -1;
}
}
public void draw() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.RED);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
g.fillOval(x, y, 20, 20);
g.dispose();
bs.show();
}
}
}
Попробуй это:
Делать BufferedImage
в вашем myPanel
класс как это:
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Теперь нарисуйте это изображение ВЫШЕ все остальное в вашем методе рисования следующим образом:
public void draw(){ BufferStrategy bs = getBufferStrategy(); if (bs== null){ createBufferStrategy(3); return; } Graphics g = bs.getDrawGraphics(); g.drawImage(image, 0, 0, getWidth(), getHeight(), null); // Draw your other stuff after this... g.fillOval(20, 20, 20, 20); g.dispose(); bs.show(); }
Это нарисует черный фон на экране, чтобы он больше не мерцал. Теперь вы можете нарисовать что-нибудь поверх этого изображения.