Piszę aplikację java, która musi płynnie przesuwać przebieg na ekranie. Spędziłem całe wieki, przechodząc przez różne samouczki, aby dowiedzieć się, jak uczynić tę animację tak płynną, jak to tylko możliwe. O ile widzę, zrobiłem wszystkie normalne rzeczy, aby wyeliminować migotanie (rysowanie do bufora poza ekranem i renderowanie w jednym kroku, plus nadpisywanie aktualizacji, więc ekran nie jest wygaszony), ale moja animacja nadal migocze, a ekran wygląda na to, że jest on pusty przed każdą aktualizacją.Jak wyeliminować migotanie animacji java
Jestem pewien, że jest coś fundamentalnego (i prawdopodobnie prostego), którego mi brakuje, ale brakuje mi pomysłów. Opublikuję poniżej klasę, która ilustruje problem. Każda pomoc byłaby bardzo cenna.
import java.awt.*;
import javax.swing.*;
public class FlickerPanel extends JPanel implements Runnable {
private float [] pixelMap = new float[0];
/** Cached graphics objects so we can control our animation to reduce flicker **/
private Image screenBuffer;
private Graphics bufferGraphics;
public FlickerPanel() {
Thread t = new Thread(this);
t.start();
}
private float addNoise() {
return (float)((Math.random()*2)-1);
}
private synchronized void advance() {
if (pixelMap == null || pixelMap.length == 0) return;
float [] newPixelMap = new float[pixelMap.length];
for (int i=1;i<pixelMap.length;i++) {
newPixelMap[i-1] = pixelMap[i];
}
newPixelMap[newPixelMap.length-1] = addNoise();
pixelMap = newPixelMap;
}
public void run() {
while (true) {
advance();
repaint();
try {
Thread.sleep(25);
} catch (InterruptedException e) {}
}
}
private int getY (float height) {
double proportion = (1-height)/2;
return (int)(getHeight()*proportion);
}
public void paint (Graphics g) {
if (screenBuffer == null || screenBuffer.getWidth(this) != getWidth() || screenBuffer.getHeight(this) != getHeight()) {
screenBuffer = createImage(getWidth(), getHeight());
bufferGraphics = screenBuffer.getGraphics();
}
if (pixelMap == null || getWidth() != pixelMap.length) {
pixelMap = new float[getWidth()];
}
bufferGraphics.setColor(Color.BLACK);
bufferGraphics.fillRect(0, 0, getWidth(), getHeight());
bufferGraphics.setColor(Color.GREEN);
int lastX = 0;
int lastY = getHeight()/2;
for (int x=0;x<pixelMap.length;x++) {
int y = getY(pixelMap[x]);
bufferGraphics.drawLine(lastX, lastY, x, y);
lastX = x;
lastY = y;
}
g.drawImage(screenBuffer, 0, 0, this);
}
public void update (Graphics g) {
paint(g);
}
public static void main (String [] args) {
JFrame frame = new JFrame("Flicker test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new FlickerPanel());
frame.setSize(500,300);
frame.setVisible(true);
}
}
Nie mogę znaleźć żadnego problemu z Twoim kodem. Wygląda całkiem gładko na moim pulpicie. ps. Możesz to zrobić znacznie wydajniej, mając tylko jedną pikselapię i używając jej jako cyklicznego bufora oraz chroniąc dostęp do niej za pomocą zsynchronizowanego bloku. W trakcie tworzenia nowej struktury każda aktualizacja powinna być OK. – Adam
+1 dla [sscce] (http://sscce.org/). Na mojej platformie mieni się bardzo źle. – trashgod
Po zagraniu nieco więcej wygląda na to, że niektóre problemy mogą wynikać z modyfikacji struktury danych pixelMap w trakcie malowania, więc rozdzierałem się między różnymi częściami ekranu. Wykonanie clone() z pixelMap na początku metody malowania wydaje się poprawiać, ale migotanie wciąż istnieje, więc nie sądzę, że to jest cała odpowiedź. –