Swing Verzögerung von repaint() umgehen

Status
Nicht offen für weitere Antworten.

Painii

Bekanntes Mitglied
Hi,
Ich bin dabei mir ein Tetris zu schreiben (bzw. schon ziemlich fertig damit).
Ich habe 1 Thread der das Spiel laufen lässt (Steine fallen runter) und einen Keylistener für links/rechts/drehen.

Beide greifen auf die Methode move() zu, die dann mein Spiel bewegt etc.
in move() wird nachdem die Sachen bewegt wurden repaint() aufgerufen.
Mein printer zeichnet einfach stur das Feld vom Spiel.

Das Problem: repaint() ruft paint() nicht immer sofort auf, und so passiert es dass wenn ich die links/rechts pfeile gedrückt halte die figuren mal komplett über den Bildschirm fliegen ohne einen Zwischenschritt anzuzeigen.

Ich hoffe ihr könnt mir folgen, hier die Funktionen dazu:
Keylistener:
Java:
public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub
        //if(pressed)return;
        if(e.getKeyCode()==KeyEvent.VK_UP){
            this.main.move("drehen");
        }
        if(e.getKeyCode()==KeyEvent.VK_DOWN){
            this.main.move("fallen");
        }
        if(e.getKeyCode()==KeyEvent.VK_LEFT){
            this.main.move("links");
        }
        if(e.getKeyCode()==KeyEvent.VK_RIGHT){
            this.main.move("rechts");
        }
        pressed = true;
        
    }
run und move:
Java:
public void run() {
        this.repaint();
        block.enterStein();
        nextStein=new Stein(1+(int)(Math.random()*7));
        while(!ende){
            this.move("fallen");
            //System.out.println(level);
            if(reihen>10){
                reihen=0;
                level++;
            }
            try{
                Thread.sleep(500-(level*25)); //verzögerung bis zum nächsten fallen
            }
            catch(InterruptedException e){}    
        }
    }
public void move(String richtung){
        if(richtung=="fallen"){
            if(!this.block.fallen()){// Stein ist unten angekommen
                if(!this.block.enterStein(nextStein))ende=true;//Neuer Stein kann nicht gesetzt werden -> ende
                for(int i=0;i<this.block.getSpielfeld().length;i++){
                    if(this.block.zeileVoll(i)){
                        reihen++;    //volle Zeile löschen
                        this.block.clearZeile(i);
                    }
                }
                nextStein=new Stein(1+(int)(Math.random()*7));
                //System.out.println(nextStein);
            }
        }
        else this.block.move(richtung); // links, rechts, drehen
        this.repaint();

    }
paint:
Java:
public void paintComponent(Graphics g){
        //super.paint(g);
        //long anfang=System.currentTimeMillis();
        //System.out.println("Zeit seit dem letzten paint: " + (lastFall-lastRepaint));
        for(int i=0;i<this.block.getPrint().length;i++){
            for(int j=0;j<this.block.getPrint()[0].length;j++){
                if(block.getPrint()[i][j])g.setColor(farbe);
                else g.setColor(Color.WHITE);
                g.fillRect(j*groesse,i*groesse,24, 24);    
            }
        }
    }

Im Anhang mal alles kompiliert und den sourcecode damit ihr das Problem sehen könnt.
 

Anhänge

  • Blockig.zip
    24,1 KB · Aufrufe: 3

André Uhres

Top Contributor
Das Problem: repaint() ruft paint() nicht immer sofort auf, und so passiert es dass wenn ich die links/rechts pfeile gedrückt halte die figuren mal komplett über den Bildschirm fliegen ohne einen Zwischenschritt anzuzeigen.
Das dürfte normal kein Problem sein. Das eigentliche Problem bei deinem Spiel ist wohl, dass es allgemein ziemlich lahm reagiert. Wenn die Verarbeitung der KeyEvents zu lange dauert, dann kann die Erscheinung auftreten, die du beschreibst.
 

Marco13

Top Contributor
Naja, je nachdem ... wenn man eine Taste gedrückt hält, kommen ggf. 30 mal pro Sekunde Events an - man kann nicht davon ausgehen, dass deswegen auch 30 mal pro Sekunde neu gezeichnet wird (sollte, vielleicht, geht auch vielleicht, aber falls irgendeine Berechnung auch nur ein bißchen bremst, wird das nicht ganz hinhauen...)
 

Marco13

Top Contributor
Hab's gerade mal kurz angeschaut und gestartet - um nachzuvolziehen, was GENAU da gemacht wird, ist es ein bißchen zu spät, aber das, was da in Strinblock.refresh und refreshSpiel gemacht wird, sieht schonmal aufwändig aus...
Dass da Exceptions verwendet werden, wenn es auch eine Abfrage "if (x<grenze)" tun würde ist nicht so gut. Und Strings sollte man nicht mit ==, sondern mit equals vergleichen. (Hat aber mit dem Problem nicht direkt was zu tun)
 

0x7F800000

Top Contributor
Code:
  if(richtung=="fallen"){
  }
das ist aber verwirrend, fehleranfällig und gruselig. Vertraust du wirklich so sehr auf diese ganzen vom compiler vorgenommenen Otimierungen und String-pools und solchen kram?! :eek: Ich muss zugeben: ich würde spontan nicht garantieren, dass solche stunts funktionieren :noe:
Benutze doch irgendwelche statische Integer-konstanten, wenn du unbedingt irgendwelche richtungen speichern willst...

André Uhres hat gesagt.:
Das eigentliche Problem bei deinem Spiel ist wohl, dass es allgemein ziemlich lahm reagiert. Wenn die Verarbeitung der KeyEvents zu lange dauert, dann kann die Erscheinung auftreten, die du beschreibst.
Ich hab jetzt nach irgendeinem Denkfehler in den ganzen Threads gesucht, bis ich dann auf "Steinblock"-Klasse gestoßen bin: bei jedem klick werden da ohne ende irgendwelche Felder refresht und deallokiert und wieder allokiert und befüllt und der Geier weiß was sonst noch :shock: => da sah es für mich so aus, als ob André Uhres's Vermutung zutreffen würde... Der Task-manager zeigt aber eine Auslastung von 5-7% an, also sieht es für mich dann doch nicht so aus, dass diese ganze allokiererei-deallokiererei meinen rechner überfordern würde. kA wo das Problem ist ???:L
Wahrscheinlich sollte man hier auf Spacerat's Signatur verweisen:
"Kaum macht man's richtig.... geht's!"
ich vermute mal, dass es hier auch so sein wird, wenn man im code ein bisschen aufräumt.
So ist er schwer zu lesen, die ganzen bezeichner sind merkwürdig, und denglisch macht's noch schwerer ;( ...Ich geh pennen^^
 

André Uhres

Top Contributor
da sah es für mich so aus, als ob André Uhres's Vermutung zutreffen würde... Der Task-manager zeigt aber eine Auslastung von 5-7% an, also sieht es für mich dann doch nicht so aus, dass diese ganze allokiererei-deallokiererei meinen rechner überfordern würde.
Ich dachte mehr an die relative Verarbeitungszeit der KeyEvents, nicht so sehr an eine Überforderung des Rechners. Ein Profiler könnte vielleicht mehr aussagen...
 

Painii

Bekanntes Mitglied
Ich dachte mehr an die relative Verarbeitungszeit der KeyEvents, nicht so sehr an eine Überforderung des Rechners. Ein Profiler könnte vielleicht mehr aussagen...


Ja ich glaub auch dass es an den KeyEvents liegt.
Ich halte eine Taste gedrückt -> bis zu 30 KeyEvents pro Sekunde bei mir.
So schnell kann ich nicht neu zeichnen, das ist klar.
Jetzt weiss ich aber nicht wie ich das ganze am dümmsten löse...
Ich würde es gerne sehen dass meine Steine alle x Sekunden fallen, und das auch wirklich gezeichnet wird - hab ich schon ausprobiert (zeit seit letzem event>400 ms -> Stein wieder fallen lassen), aber trotzdem ist das ganze manchmal gesprungen, weil repaint() nicht in bestimmten Intervallen gerufen wird, sondern manchmal schnell kommt und manchmal erst später aufgerufen wird.


Und ich will mich auch entschuldigen dass mein code so schlecht ist, ich schau meistens erst wenn ich alles fertig geschrieben hab dass es schöne Namen etc. gibt, bau dann ne Dokumentation und alles. Bisher musste ich ja noch niemanden während der Entwicklung reinschauen lassen :oops:
 

babuschka

Top Contributor
Die Lösung hierfür wäre, dass Du bei einem Tastendruck ein boolean-Flag setzt und dieses zu gegebener Zeit in deiner Spielschleife abfragst.
Selbst wenn dann 100 KeyEvents innerhalb von einem Schleifendurchlauf ausgelöst werden wird nur einmal an geeigneter Stelle darauf reagiert.
 

Painii

Bekanntes Mitglied
Die Lösung hierfür wäre, dass Du bei einem Tastendruck ein boolean-Flag setzt und dieses zu gegebener Zeit in deiner Spielschleife abfragst.
Ok, das hab ich jetzt gemacht.
Mein Thread/KeyEvent geht ja auf die Methode move().
Da hab ich einfach ein boolean flag so gebaut:

Java:
public void move(richtung){ 
 if(flag)return; //move wird schon gezeichnet   
flag=true; //move wird ausgeführt   
{
 //Stein in die richtung schieben 
}   
repaint(); 
 while(flag){} // warte bis der stein gezeichnet wurde  
} 
public void paintComponent([U]Graphics [/U]g){  
 //male   
flag=false; 
}

Das funktioniert auch ganz nett solange nur mein normaler Thread die Steine fallen lässt, aber sobald ich eine Taste drücke ist es aus, mein move geht in die Endlosschleife aber offensichtlich wird kein paint mehr aufgerufen.

edit: es hilft auch nicht repaint() in die schleife zu legen
 
Zuletzt bearbeitet:

babuschka

Top Contributor
Ich meinte damit eigentlich, dass Du in der Listener-Methode ein Flag setzt. Z.B. so:
Java:
if(e.getKeyCode()==KeyEvent.VK_DOWN){
            fall=true;
        }

Dann sieht Dein Game Loop etwa folgendermaßen aus:
Java:
while(!ende){
            move();
            //System.out.println(level);
            if(reihen>10){
                reihen=0;
                level++;
            }
            repaint();
            try{
                Thread.sleep(500-(level*25)); //verzögerung bis zum nächsten fallen
            }
            catch(InterruptedException e){}    
        }

und in Move reagierst Du auf die Benutzereingaben
Java:
public void move(){ 
if(darfBewegen){ //Der Stein darf bewegt werden
 if(fall){
 //Code für Fallen
 }if(left){
 //Code für links
 }
 //... weiterer Code
} 
}
Außerdem solltest Du noch dafür sorgen, dass das Bewegungs-Flag an geeigneter Stelle wieder auf false gesetzt wird.

Ich übernehme keine Garantie dafür, dass der Code so funktioniert. Er ist eher dafür gedacht, Dir ein paar Anhaltspunkte zu geben.
 

Marco13

Top Contributor
Diese Struktur würde aber bewirken, dass auch die Bewegung nach links und rechts nur alle 400ms ausgeführt wird...
 

0x7F800000

Top Contributor
Diese Struktur würde aber bewirken, dass auch die Bewegung nach links und rechts nur alle 400ms ausgeführt wird...
Nja.. und der game-loop sollte eigentlich immer permanent so schnell rasen wie es nur geht, um alle angesammelten benutzereingaben möglichst augenblicklich abarbeiten zu können. Dieses "runterfallen" würde ich dagegen in einem kleinen separaten thread erledigen. Dieser thread macht dann nichts anderes, als alle ~0.5 sekunden einen flag "FALL" auf true zu setzen, was dann von der rasenden move-methode ein paar millisekunden danach erkannt wird, und dieser Flag abgearbeitet und zurückgesetzt wird.
 

0x7F800000

Top Contributor
Genau DAfür wären ja eigentlich die Events gut - alles andere wäre ja eine Art "polling" ... ???:L
Joah. Aber bei spielen, wo es eh drum geht physik in möglichst feinen schritten zu simulieren, KI-entscheidungen möglichs oft neuzuberechnen, und das Bild für flüssige bewegung möglichst oft neuzuzeichnen, ist es imho nicht ganz angebracht da auch noch irgendwelche events mit reinzuweben: wird doch eh alles 60 mal pro sekunde aktualisiert... Oder ist diese Meine Vorstellung komplett daneben? ???:L Lasse mich gerne von anderen Modellen überzeugen...
 

Marco13

Top Contributor
Hm. Bei Tetris ist das ja nicht der Fall (die meiste Zeit über macht das Tetris das, was PC heutzutage die meiste Zeit über machen: Warten). Bei einer Echtzeitsimulation muss man natürlich zusehen, wie man die Events da passend "reinwebt"...
 

Painii

Bekanntes Mitglied
Naja ich glaub es gibt jetzt verschiedene Probleme:
1. Fallen durch gameloop, das geht ja ganz gut, einfach nach dem fallen ein sleep und fertig.
2. Fallen durch Tastendruck, das kann meinetwegen beliebig schnell gehen
3. Nach links/rechts bewegen: Es sollte so gut wie sofort erledigt werden, aber:
-Nachdem eine Bewegung gemacht wurde muss das Bild ja solang "anhalten", dass man menschlich auch sehen kann wenn sich der Stein bewegt (Wenn das bewegen selbst nach 30ms gezeichnet wurde könnte da schon eine neue Bewegung kommen, und 30ms ist mir zu wenig Reaktionszeit um zu sehen dass sich der Stein bewegt hat).
Eine feste Zeit zu warten ist aber auch doof, weil einerseits ich ja durch eine statische Zeit nicht garantieren kann dass schon neu gezeichnet wurde, andererseits das fallen ja immer schneller vonstatten geht (je höher das level), und irgendwann könnte ich nichtmehr einen Stein von links nach rechts bekommen bevor er durchgefallen ist.

Deswegen hab ich ja gedacht, nachdem ein move gemacht wurde setzt ich mein flag auf true, rufe repaint und gehe in eine schleife die solang läuft bis mein flag wieder false ist.
paint sollte das flag auf false setzen.
Aber das funktioniert irgendwie nicht richtig. (siehe letzter post).

Kann ich irgendwie meine move()-funktion solange aussetzen bis mein paint fertig gezeichnet hat, ohne in eine Endlosschleife zu gehen?
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
L JavaFX Verzögerung beim Laden von Daten AWT, Swing, JavaFX & SWT 6
J JavaFX Tooltip Verzögerung beim ersten Anzeigen AWT, Swing, JavaFX & SWT 4
S Verzögerung zwischen Cursorbewegung einbauen AWT, Swing, JavaFX & SWT 1
E Swing Verzögerung beim Hinzufügen / Ändern von Swingkomponenten AWT, Swing, JavaFX & SWT 3
F Verzögerung bei der ersten Anzeige AWT, Swing, JavaFX & SWT 6
J Verzögerung bei Änderungen der Anzeige abwarten AWT, Swing, JavaFX & SWT 5
hdi Problem mit ToolTip: Aussehen/Verzögerung AWT, Swing, JavaFX & SWT 7
W Verzögerung à la Tooltip bei mouseEntered AWT, Swing, JavaFX & SWT 19
D Repaint Funktioniert nicht AWT, Swing, JavaFX & SWT 2
D JUNG Repaint function does not work AWT, Swing, JavaFX & SWT 2
E repaint Probleme AWT, Swing, JavaFX & SWT 13
G listener repaint() - verschiedene Darstellung AWT, Swing, JavaFX & SWT 24
ExceptionOfExpectation Textdarstellung auf einem Canvas mit Hilfe von repaint(); AWT, Swing, JavaFX & SWT 6
J actionperformed wird nicht aufgerufen/ repaint() AWT, Swing, JavaFX & SWT 6
L Swing repaint() ruft paintComponent(g1d) nicht auf AWT, Swing, JavaFX & SWT 12
G Repaint wird nicht durchgeführt AWT, Swing, JavaFX & SWT 8
I Swing Verhindern, dass repaint() kaskadiert AWT, Swing, JavaFX & SWT 6
ms_cikar Update swingUtilities Repaint in der Schleife AWT, Swing, JavaFX & SWT 3
T Swing Probleme mit repaint() bzw. JScrollPane AWT, Swing, JavaFX & SWT 7
N Swing JButtons werden nach repaint() doppelt dargestellt AWT, Swing, JavaFX & SWT 12
K Methode repaint() AWT, Swing, JavaFX & SWT 1
B Swing Wann brauche ich repaint() ? AWT, Swing, JavaFX & SWT 1
javampir Swing repaint in JavaFX Anwendung AWT, Swing, JavaFX & SWT 3
A repaint(); AWT, Swing, JavaFX & SWT 9
J Swing ungewünschter Nebeneffekt bei der repaint() Methode AWT, Swing, JavaFX & SWT 3
A Problem: repaint() - Schleife AWT, Swing, JavaFX & SWT 3
S 2D-Grafik repaint()-Aufruf. Und nichts geschieht. AWT, Swing, JavaFX & SWT 5
Joew0815 JDialog repaint() funktioniert nicht wie gewünscht. AWT, Swing, JavaFX & SWT 2
P JPanel und Repaint AWT, Swing, JavaFX & SWT 5
J JavaFX Automatisches Neuzeichnen ("Repaint") abstellen. AWT, Swing, JavaFX & SWT 10
F JTable Repaint Issue AWT, Swing, JavaFX & SWT 1
N Observer: update ruft nicht repaint auf AWT, Swing, JavaFX & SWT 0
C Repaint() funktioniert nicht in TabbedPanel AWT, Swing, JavaFX & SWT 5
S JList repaint AWT, Swing, JavaFX & SWT 1
L NullpointerException und Probleme mit repaint() AWT, Swing, JavaFX & SWT 11
M Repaint mittels Button richtig aufrufen klappt nicht AWT, Swing, JavaFX & SWT 1
B Repaint auf JFrame, JLabel und ImageIcon AWT, Swing, JavaFX & SWT 4
K 2D-Grafik Paint - Wie binde ich repaint ein? AWT, Swing, JavaFX & SWT 8
D repaint() klappt anders als vorgestellt AWT, Swing, JavaFX & SWT 15
R Repaint() in Schleifen, Threads AWT, Swing, JavaFX & SWT 13
B Swing Repaint Problem - mal wieder AWT, Swing, JavaFX & SWT 5
P 2D-Grafik Gezielter Repaint einzelner Frames in Java-Game AWT, Swing, JavaFX & SWT 6
javampir Bei repaint nix los AWT, Swing, JavaFX & SWT 2
B Swing repaint() AWT, Swing, JavaFX & SWT 3
Ernesto95 AnimationLoop - Problem bei Aufruf von repaint AWT, Swing, JavaFX & SWT 6
P 2D-Grafik repaint(); steigender RAM Verbauch AWT, Swing, JavaFX & SWT 6
Y KeyListener, GUI Thread, repaint AWT, Swing, JavaFX & SWT 7
S Applet Repaint AWT, Swing, JavaFX & SWT 3
M Programm hängt sich auf nachdem repaint() benutzt wurde AWT, Swing, JavaFX & SWT 2
R Swing Grafikfehler bei repaint AWT, Swing, JavaFX & SWT 2
N repaint() blockieren AWT, Swing, JavaFX & SWT 6
K canvas zeig nach repaint nichts an AWT, Swing, JavaFX & SWT 8
M Repaint() AWT, Swing, JavaFX & SWT 14
J Swing repaint, repaint, repaint AWT, Swing, JavaFX & SWT 8
M Applet repaint() verlangsamen AWT, Swing, JavaFX & SWT 7
R paintComponent malt bei repaint() Rahmen um Panel AWT, Swing, JavaFX & SWT 7
P EDT Problem? Kein Aufruf der repaint Methode AWT, Swing, JavaFX & SWT 6
V Applet JApplet Flackern durch Repaint AWT, Swing, JavaFX & SWT 11
kodela Problem mit repaint() AWT, Swing, JavaFX & SWT 3
N Swing Funktion repaint() updated nicht AWT, Swing, JavaFX & SWT 5
F repaint reagiert nicht AWT, Swing, JavaFX & SWT 8
S AWT Probleme mit repaint() AWT, Swing, JavaFX & SWT 2
D Repaint()? Oder was??? AWT, Swing, JavaFX & SWT 5
M Eine nicht korrekte Darstellung bei repaint() warum? AWT, Swing, JavaFX & SWT 4
T 2D-Grafik Kreis "von Hand" zeichnen -> jedesmal repaint()? AWT, Swing, JavaFX & SWT 6
R validate(), repaint funktionieren nicht! AWT, Swing, JavaFX & SWT 7
B AWT Canvas überdeckt nach repaint() JComboBox-Optionen AWT, Swing, JavaFX & SWT 2
B Swing verschachteltes GUI: repaint() ändert mehr als nur gewünschte Component AWT, Swing, JavaFX & SWT 4
S validate(), invalidate(), repaint(),... Was kommt wann? AWT, Swing, JavaFX & SWT 5
M 2D-Grafik repaint() löscht altes Bild nicht AWT, Swing, JavaFX & SWT 2
J repaint() nicht richtig? AWT, Swing, JavaFX & SWT 6
R repaint erzwingen AWT, Swing, JavaFX & SWT 3
Zettelkasten repaint() von anderen Klassen aufrufen AWT, Swing, JavaFX & SWT 4
H repaint()-Problem - 50% CPU-Auslastung AWT, Swing, JavaFX & SWT 4
P repaint während Thread läuft AWT, Swing, JavaFX & SWT 9
D Repaint Frage, Design Frage AWT, Swing, JavaFX & SWT 2
N Swing MainWindow(JFrame) aktualisieren(neuzeichnen) repaint AWT, Swing, JavaFX & SWT 4
T repaint() Problem AWT, Swing, JavaFX & SWT 2
A 2D-Grafik Repaint - Alternative? AWT, Swing, JavaFX & SWT 3
C JLabel, JTextArea, JScrollPane. repaint(); ? AWT, Swing, JavaFX & SWT 6
N Swing repaint() funktioniert nicht AWT, Swing, JavaFX & SWT 5
T Swing repaint funktioniert nur manchmal? AWT, Swing, JavaFX & SWT 6
K Jpanel repaint problem (Fullscreen) AWT, Swing, JavaFX & SWT 5
V Swing Bei repaint() tut sich nichts AWT, Swing, JavaFX & SWT 7
G ColorReader, bei Fadenkreuz zeichnen mit repaint() flackern AWT, Swing, JavaFX & SWT 19
I Canvas Repaint Probleme AWT, Swing, JavaFX & SWT 2
D Swing Actionlistener verhindert repaint?! AWT, Swing, JavaFX & SWT 2
S JLabel repaint AWT, Swing, JavaFX & SWT 8
C Swing Linux mag mein Swing-repaint() nicht... AWT, Swing, JavaFX & SWT 7
J Swing paintComponent() - repaint() - BufferedImage anzeigen AWT, Swing, JavaFX & SWT 5
Luk10 repaint() auch in anderen Klassen! AWT, Swing, JavaFX & SWT 6
A repaint() zu langsam, bitte um alternativen AWT, Swing, JavaFX & SWT 5
T Überlappende Transparenz und repaint() AWT, Swing, JavaFX & SWT 10
E EINFACHE Verständnisfrage zu repaint(), paintComponent(), usw. AWT, Swing, JavaFX & SWT 16
O Girdbag Formatierung nach repaint verloren AWT, Swing, JavaFX & SWT 2
E Swing - repaint() AWT, Swing, JavaFX & SWT 6
T Image wird nicht angezeigt?! - MediaTracker/repaint AWT, Swing, JavaFX & SWT 9
E AWT Problem mit Repaint (in Loop oder Timer) AWT, Swing, JavaFX & SWT 3
O Exception bei repaint AWT, Swing, JavaFX & SWT 3
D Fragen zu Swing, paintComponent() und repaint AWT, Swing, JavaFX & SWT 6

Ähnliche Java Themen


Oben