Double Buffering, update(Graphics) wird nicht aufgerufen

Math_student

Grünschnabel
Hallo zusammen,
ich habe ein kleines Problem mit dem Double Buffering. Und zwar programmiere ich zurzeit ein kleines 2D Spiel und vor einiger Zeit hat es dann angefangen zu "flackern".. Ein bisschen im Internet gesucht und zum Schluss gekommen dass Double Buffering die Lösung sei. Das hab ich dann auch so einprogrammiert, aber meine Update Mathode für das JPanel wird irgendwie nicht durch repaint() aufgerufen..
Am besten ich poste mal das Programm..

Code:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class World extends JPanel implements Runnable{
   
    JFrame f;
    Labyrinth l;
    Player p;
    long lastFrame=System.currentTimeMillis();
   
    int obere_eckex=0;
    int obere_eckey=0;
    //DB=Double Buffering
    private Image dbImage;
    private Graphics dbGraphics;
   
   
    World(int width, int height, Player p){
        this.setSize(width, height);
   
        f=new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800, 600);
        f.setVisible(true);
        f.setResizable(false);
        f.add(this);
       
        l=new Labyrinth();
        l.constructLab();
        f.addKeyListener(p.key);
        this.p=p;
        p.l=l;
        Thread th=new Thread(this);
        th.start();
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
           
            long thisFrame=System.currentTimeMillis();
            float timesincelastframe=(float)(thisFrame-lastFrame)/1000f;
            lastFrame=thisFrame;
            repaint();
           
            p.update(timesincelastframe);
            for(int i=0;i<p.bullets.size();i++){
                p.bullets.get(i).update(timesincelastframe);
            }

           
           
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    //DB
    public void update(Graphics g){
        
        //Double Buffer initialisieren
        if(dbImage==null){
            dbImage=createImage(this.getSize().width, this.getSize().height);
            dbGraphics=dbImage.getGraphics();
        }
        //Hintergrund löschen
        dbGraphics.setColor(getBackground());
        dbGraphics.fillRect(this.getX(), this.getY(), this.getSize().width, this.getSize().height);
        //Vordergrund zeichnen
        dbGraphics.setColor(getForeground());
        paint(dbGraphics);
        //Offscreen anzeigen
        g.drawImage(dbImage, this.getX(), this.getY(), this);
    }
   
    public void paint(Graphics g){
       
        super.paint(g);
       
        if(p.posx>=400){
            this.setBounds(-((int)p.posx-400),obere_eckey,8000,6000);
            obere_eckex=-((int)p.posx-400);
           
        }
        if(p.posy>=300){
            this.
            setBounds(obere_eckex,-((int)p.posy-300),8000,6000);
            obere_eckey=-((int)p.posy-300);
        }
       
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 8000, 6000);
        g.setColor(Color.gray);
        for(int i=0;i<l.labyrinth.size();i++){
            g.fillRect(l.labyrinth.get(i).x,l.labyrinth.get(i).y, l.labyrinth.get(i).width,l.labyrinth.get(i).height);
        }
        g.setColor(Color.red);
        for(int i=0;i<p.bullets.size();i++){
            g.fillOval((int)p.bullets.get(i).posx, (int)p.bullets.get(i).posy, p.bullets.get(i).width, p.bullets.get(i).height);
        }
        g.setColor(Color.BLACK);
        g.fillRect((int)p.posx, (int)p.posy, p.width, p.height);
    }
   
    public static void main(String[] args){
        Player p=new Player(1200,500,50,50);
        new World(800,600,p);
    }

}

Es sollte ein Labyrinthspiel werden indem es ein riesiges Spielfeld gibt und der Bildausschnitt mit dem Spieler mitwandert.
Ich weiß es gibt vermutlich einige Schönheitsfehler, ich bitte deshalb um etwas Nachsicht. .

Viele Grüße
 
Hi

a)
du teilst deinen Swing-verwendenden Code auf mehrere Threads auf. Sollte man nicht machen, weil Swing damit nicht umgehen kann und das zu beliebigen Probleme führen kann. Als einfache Abhilfe, pack alles Grafikbezogene aus "anderen Threads" (also zB. das repaint(); in run) in solche Blöcke:
Java:
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
       //Grafikcode hier
    }
});
Das managed im Hintergrund, dass der Grafikcode in der richtigen Umgebung ausgeführt wird. Es kann aus jedem Thread aufgerufen werden, auch aus dem "Richtigen", wo man direkt auf die Grafiksachen zugreifen darf. Zu beachten dabei ist aber, dass dadurch die Ausführung verzögert werden kann, also die nächsten Codezeilen werden evt. vor dem Inhalt von dem Block (oder gleichzeitig) ausgeführt.
Um die Reihenfolge bei Bedarf nicht durcheinander zu bringen kann man invokeAndWait statt invokeLater verwenden, allerdings darf das nur in "falschen" Threads verwendet werden, ein invokeAndWait im richtigen Thread wirft immer Exceptions.

b)
Zum DoubleBuffering, Swing hat sowas schon eingebaut. Fraglich, ob die manuelle Variante irgendwas verbessert. Abe rausprobieren schadet nicht, vllt. reichts ja wirklich als Abhilfe für das Flackern (so genau trau ich mich das bei Swing nicht sagen, das macht was es will :D)
 
Vielen Dank für die Antwort,
ja das mit Swing werde ich auf jeden Fall mal ausprobieren, hab mit Swing allerdings noch wenig Erfahrung und müsste mich da erstmal noch über alle Möglichkeiten informieren. Aber ich würde auch gern wissen wie man das Double Buffering selbst programmieren kann. Normalerweise müsste ja durch das repaint() in der Methode run() automatisch die update(Graphics) Methode des JPanel-Objektes aufgerufen werden.. In meinem Fall passiert das aber nicht. Woran kann das liegen?
 
Nur um sicherzugehen, weil sich der Beitrag etwas seltsam anhört:
Swing ist nichts Neues, nur der Sammelbegriff für JPanel, JButton, J...

Woran kann das liegen?
Wie gesagt ist Swing nicht threadsafe. Punkt a von meinem vorigen Beitrag ist ein Fehler
und sollte ausgebessert werden, sonst kann noch viel mehr danebengehen.
Änder es doch einfach einmal, vielleicht war das das einzige Problem.
 
Zurück