# repaint() ruckelt



## Marlon (22. Feb 2008)

So, beschäftige mich nun schon seit längerem mit der Spieleprogrammierung in Java.
Zur Zeit hänge ich an einem Echtzeit Java Applet.
Mein Problem geht mir eigentlich schon was länger auf den Keks und ich bin mir sicher der ein oder andere wird bei meinem Thread sicher die Augen verdrehen.
Das Problem ist ganz einfach:
Ich male mehrere Objekte in mein Appletpanel, die alle gezeichnet werden müssen.
Ich rufe ein repaint() für jeden Bereich im Applet auf, der neugezeichnet werden muss.
Das verbraucht ziemlich viele Recourcen, wie ich bereits getestet habe und führt dazu, dass das Spiel ruckelt.
Ich habe es schon mit DoubleBuffering und der Clipping Methode versucht, aber das bringt alles nichts.
Wenn es hilft kann ich auch Code posten, aber vielleicht gibt es eine andere, bessere Methode.
Vielen Dank schonmal für Tipps!
Marlon


----------



## tuxedo (22. Feb 2008)

Was läuft denn in der paint Methode ab? Hast du da vielleicht verschwenderisch gecodet?

Was zeichnest du und vor allem wie zeichnest du?

- Alex


----------



## Marlon (22. Feb 2008)

alex0801 hat gesagt.:
			
		

> Was läuft denn in der paint Methode ab? Hast du da vielleicht verschwenderisch gecodet?
> 
> Was zeichnest du und vor allem wie zeichnest du?
> 
> - Alex



ich zeichne mehrere objekte, die ihrerseits eine paint(g) methode implementieren


```
//paint panel
	public class MainPanel extends JPanel {	
		public void update(Graphics g) {
			paint(g);
		}
		
	    public void paint(Graphics g) {
			super.paintComponents(g);
			paintObjects(g);
	    }
	}
	
	private void paintObjects(Graphics g) {
		g.setColor(new Color(84, 43, 11));
		g.fillRect(0, 0, appletWidth, appletHeight);

		for(int i=0;i<MainController.getInstance().objectsize();i++) {	
			paintObject((VisibleObject)(MainController.getInstance().getObject(i)), g);
		}
	}

	//actually paints the objects
	public void paintObject(VisibleObject obj, Graphics g) {
		obj.paint(g);
		
		if(obj.getImage()!=null) {
			g.drawImage(obj.getImage().getImage(), obj.getXOnScreen(),
					obj.getYOnScreen(), obj.getWidth(), obj.getHeight(), this);
		}

		for(int i=0;i<obj.objectSize();i++) {
			paintObject((VisibleObject)obj.getObject(i), g);
		}
	}


private run() {
		for(int i=0;i<objectsize();i++) {
			updateObject(getObject(i));
			repaint(getObject(i).getXOnScreen()-1, getObject(i).getYOnScreen()-1,
					getObject(i).getWidth()+1, getObject(i).getHeight()+h1);
		}}
```

[/code]


----------



## tuxedo (22. Feb 2008)

Naja, bin in solchen Sachen auch nicht der optimierungsprofi. Aber vermeide möglichst "new" in Schleifen (da ständig neu gezeichnet wird ist das quasi auch ne Schleife). Das Color-Objekt könntest du einmal global anlegen statt immer wieder mit "new" neu zu machen.


- Alex


----------



## Quaxli (22. Feb 2008)

Diesen Mehrfachaufruf könntest Du auch noch rauswerfen:


```
//paint panel
   public class MainPanel extends JPanel {   
      public void update(Graphics g) {
         paint(g);
      }
      
       public void paint(Graphics g) {
         super.paintComponents(g);
         paintObjects(g);
       }
   }
```

Stattdessen:


```
//paint panel
   public class MainPanel extends JPanel {   


       public void paintComponents(Graphics g) {
         super.paintComponents(g);
         paintObjects(g);
       }
   }
```


Hier färbst Du jedesmal den Hintergrund. Laß das. setBackground(...) im Konstruktor tut's auch


```
private void paintObjects(Graphics g) {
      //g.setColor(new Color(84, 43, 11));
      //g.fillRect(0, 0, appletWidth, appletHeight);

      for(int i=0;i<MainController.getInstance().objectsize();i++) {   
         paintObject((VisibleObject)(MainController.getInstance().getObject(i)), g);
      }
   }
```


Den verstehe ich nicht ganz:



```
public void paintObject(VisibleObject obj, Graphics g) {
      obj.paint(g);
      
      if(obj.getImage()!=null) {
         g.drawImage(obj.getImage().getImage(), obj.getXOnScreen(),
               obj.getYOnScreen(), obj.getWidth(), obj.getHeight(), this);
      }

      for(int i=0;i<obj.objectSize();i++) {
         paintObject((VisibleObject)obj.getObject(i), g);
      }
   }
```

Das sieht wie ein Mehrfachaufruf aus. obj.paint(g) sollte das Objekt malen und gut. Du prüfst aber nochmal ob ein Image vorhanden ist und malst das nochmal - was wird dann beim ersten Mal gezeichnet. Und das letzte Stück Code greift wohl auf einen Vector zu und dann werden nochmal alle Objekte gezeichnet?


Guck mal in mein Tutorial, da findest Du ein Beispiel, wie man eine komplexe Animation aufziehen könnte. Link


----------



## Marlon (22. Feb 2008)

hei danke!
werd ich mir mal anschauen, ich denke das bringt mich weiter...


----------



## Marlon (22. Feb 2008)

Quaxli hat gesagt.:
			
		

> Diesen Mehrfachaufruf könntest Du auch noch rauswerfen:
> Das sieht wie ein Mehrfachaufruf aus. obj.paint(g) sollte das Objekt malen und gut. Du prüfst aber nochmal ob ein Image vorhanden ist und malst das nochmal - was wird dann beim ersten Mal gezeichnet. Und das letzte Stück Code greift wohl auf einen Vector zu und dann werden nochmal alle Objekte gezeichnet?



genauer gesagt handelt es sich hierbei um einen rekursiven aufruf. ein objekt kann in meinem spiel mehrere unterobjekte besitzen. stell dir eine kreatur vor. das ist das objekt. diese kreatur kann nun einen hut tragen. das waere dann ein unterobjekt und muss ebenfalls gezeichnet werden.


----------



## Quaxli (22. Feb 2008)

Finde ich unschön gelöst, aber das ist eher subjektiv. Ich bevorzuge pro Objekt einen paint-Aufruf. Die entsprechende Logik, wenn etwas dazu gezeichnet werden muß, ist das dann bei mir in der paint-Methode des Objektes hinterlegt. Das spart dann eine weitere Schleife. Damit ist dann auch alles in einem Objekt gekapselt.


----------



## Marlon (29. Feb 2008)

Quaxli hat gesagt.:
			
		

> Finde ich unschön gelöst, aber das ist eher subjektiv. Ich bevorzuge pro Objekt einen paint-Aufruf. Die entsprechende Logik, wenn etwas dazu gezeichnet werden muß, ist das dann bei mir in der paint-Methode des Objektes hinterlegt. Das spart dann eine weitere Schleife. Damit ist dann auch alles in einem Objekt gekapselt.



nunja, ein objekt sollte nicht unbedingt ueber seine unterobjekte bescheid wissen muessen.
so bleibt es von diesem objekt gekapselt und die unterobjekte duerfen auch in anderen objekten verwendet werden.
abgesehen davon ist mir aufgefallen, dass ich noch nicht soweit bin, dass ich unterobjekte an objekte haenge.
das heisst, die diskussion koennen wir erstmal verschieben und uns nochmal dem repaint problem widmen.

ich habe nun das double buffering getestet, so wie auf mehreren seiten im internet beschrieben.
leider hat sich an der performance nichts geaendert.
ich finde irgendwie keine loesung.
sofern auf dem bildschirm gemalt wird ruckelt es.
bei meinem kumpel flimmert es sogar stark.
auf wieder einem anderen rechner laeuft es zwar nicht ruckelig, dafuer sehr langsam...
wer weiss weiter?


----------



## Quaxli (29. Feb 2008)

Tutorial


----------



## Marco13 (29. Feb 2008)

Du machst dort den Aufruf

```
g.drawImage(obj.getImage().getImage(), obj.getXOnScreen(),
               obj.getYOnScreen(), obj.getWidth(), obj.getHeight(), this);
```
Damit wird das Bild skaliert gezeichnet. Es wäre (u.U. DEUTLICH!) schneller, wenn du das Bild nur EIN mal skalieren würdest (was kein Problem sein sollte, weil das 'obj' ja das Bild kennt, UND die Größe, die es haben muss), und dann nurnoch das fertig skalierte Bild mit

```
g.drawImage(obj.getImage().getTheImageThatWasScaledToTheDesiredSizeOnceInTheConstructorOfObj(), obj.getXOnScreen(),
               obj.getYOnScreen(), this);
```
zeichnen würdest.


----------



## Marlon (29. Feb 2008)

HA, stimmt, das wird ja jedesmal skaliert, wenn ich die groesse beim aufruf der drawimage funktion mit angebe.
dabei skaliere ich das doch in der tat im konstruktor!
ich habe mir dieses tutorial angeschaut und meine ganze paint funktionalitaet danach umgeschrieben.
das ist wirklich super (wenn auch sehr umstaendlich geloest mit dem zeichnen)!
es laeuft naemlich nun nicht mehr ruckelig sondern schoen gleichmaessig.
trotz allem laeuft es auch nie richtig schnell wenn ich das timedelay runterschraube. (was es jedoch tut, wenn ich ganz aufs zeichnen verzichte)
aber was solls, damit kann ich erstmal leben.
vielen dank also an alle!


----------

