# zu viele Objekte, Problem mit neuzeichnen.



## Fazzoletti9 (4. Mai 2009)

Guten Morgen,

ich bräuchte mal eure Professionelle Hilfe. Ich habe das Tutoriel von Quaxli komplett durchgearbeitet hat auch super geklappt (danke Quaxli). Jetzt bin ich dabei den ersten teil (das Hubschrauber Programm) so zu verändern das ich ein Programm bekomme was das macht, was ich möchte. (ich hoffe das ist in Ordnung) Ich habe das auch alles so hingekommen wie ich wollte aber ich habe ein Problem mit diesem Stückchen Code:


```
public void mauerBauer(){
		horst = new WallBuilder(tmp);
		BufferedImage[] wall = this.loadPics("pics/Mauer2.gif",1);
		for ( int zeile = 0; zeile < horst.getWall().length; zeile++ ){
		      for ( int spalte=0; spalte < horst.getWall()[zeile].length; spalte++ )
		        {    
		if(horst.getWall()[zeile][spalte]){
		mauer= new Wall(wall, zeile*8+20, spalte*8+20 ,100,this);
		}
		actors.add(mauer);
	}
```

Diese Methode ist dafür da mit ein Labyrinth zu zeichnen aus einem Bool Array welches ich vorher generiert habe. Funktioniert auch alles super, nur leider ist es so, dass das Array locker 120x120 Felder groß ist und davon geschätzt 50% mit Objekten gefüllt sind. Und diese dann bei jeden Durchlauf Zyklus neu gezeichnet werde.  Und nach meinem Verständnis ist das ein wenig zu viel Arbeit für meinen Computer. Deswegen meine Frage: Gibt es eine einfache Möglichkeit das Programm umzuschreiben, dass Die Mauerobjekte nicht bei jedem Zyklus neu gezeichnet werden sondern das die irgendwie "statisch" sind? Ich glaube das das zweite Programm aus dem Tutoriel dass irgendwie macht, aber leider habe ich bei dem Zweiten Teil nicht wirklich verstanden was ich eigentlich gemacht habe.  Wenn ihr noch mehr von meinem Code braucht, müsst ihr dass sagen bin Neuling Programmierer. 

  Mit Freundlichen Grüßen
      Ben


----------



## Quaxli (4. Mai 2009)

Wird das 120x120-Array komplett angezeigt oder nicht?

Falls ja, könnte man darüber nachdenken, daß Labyrinth in ein BufferedImage zu speichern und nur das eine Bild zu malen.

Falls nein, solltes Du den 2. Teil nochmal lesen.  Dort habe ich beschrieben, wie man vorgehen kann, um nur das zu zeichnen, was momentan angezeigt werden soll. Wenn Du hier Probleme hast, sag uns, wo genau.

In jedem Fall ist etwas mehr Input möglich. Schreib doch noch mal ein paar Details.


----------



## Fazzoletti9 (6. Mai 2009)

Jau das Array wird Komplett angezeigt, dass ist nicht das Problem. Das Problem ist das bei so großen (aber auch schon 40x40 Arrays) die Bildwiederholungsrate ins Bodenlose sinkt. 
Das Labyrinth in ein eigenes Bild zu speichern hört sich gut an, nur leider weiß ich überhaupt nicht wie ich das machen könnte. Und zusätzlich nehme ich dann mal an müsste ich dann auch wieder ein Zweites "BufferedImage" um die Kollisionsabfrage zu realisieren (Will mit einem Männchen durch das Labyrinth durch gehen können) Halt so wie in dem Zweiten teil von deinem Tutoriel.
Also wenn ihr mir da mit dem "bufferedImage" Helfen könntet wäre ich euch zu großem Dank verpflichtet.
 MfG
   Ben


----------



## Steev (11. Mai 2009)

Wie Quaxil schon geschrieben hat:

Ich würde einfach alle nötigen Bilder bei dem Start deines Programmes in ein BufferedImage rendern und dies dann immer für die Renderung verwenden.

Hilfe:

int width = deinArray.length * tileWidth;
int heigth = deinArray[0].length * tileHeight;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();

// Hier kann dann gezeichnet werden:
for (int x = 0; x < deinArray.length; x++)
  for (int y = 0; y < deinArray[0].length; y++)
    g2.drawImage(tileReference[deinArray[x][y]], x * tileWidth, y * tileWidth, null);


----------



## newcron (14. Mai 2009)

Das Problem, dass du da hast ist ganz typisch für fast alle spiele (und auch anderen grafikintensiven Applikationen). Den gesamten Hintergrund in ein Bild zu rendern ist nicht unbedingt eine gute Lösung: erstens verbraucht das ne Menge Speicher und zweitens kommst du damit in Probleme, wenn die Aktuelle Karte größer als der Bildschirm ist - dann verbraucht der Ansatz nämlich erst recht viel speicher...

Was du tun musst ist, dir vor jedem Zeichendurchlauf zu überlegen, welche Teile des Bildschirms sich verändert haben. Hat sich beispielsweise nur deine Hauptfigur bewegt, musst du nur die alte Position (wo vorher die Figur war) und neue Position neu zeichnen. Den Rest kannst du dir sparen. 

Swing unterstützt das bereits. Es gibt eine repaint() methode, die die neu zu zeichnende Fläche als Parameter bekommt (x,y, breite, höhe). Diese rufst du einfach statt der normalen Repaint Methode auf. In der Paint Methode musst du dann den Clipping bereich mittels g.getClip() abfragen und brauchst dann nur das zeichnen, was sich darin befindet. Eine Lösung, die dir hierbei helfen könnte, wären Quadtrees. Damit organisierst du deine Spielszene in logische bereiche und kannst sehr einfach entscheiden, was neugezeichnet werden muss.


----------



## Steev (15. Mai 2009)

Korrekt währe es, hier wie bei einer TileMap zu verfahren:

Also errechnen, welcher Teil der Map gerendert werden muss. Dann würde ich, wie oben schon geschrieben, die einzelnen Tiles in ein BufferedImage zeichnen und dieses BufferedImage auf den Bildschirm zeichnen.
Hierbei ist es, wie newcron schon geschrieben hat, wichtig, dass berechnet wird, welche Tiles sich geändert haben. Also solltest du das BufferedImage mit den Tiles nur dann neu zeichnen lassen, wenn sich der Inhalt geändert hat. Damit wird das Neuzeichnen der einzelnen Tiles nur auf das nötigste beschränkt.
Um den Zeichenvorgang noch weiter zu beschleunigen, würde ich dann berechnen, um wie viele Tiles sich die Ansicht zu der vorherigen Ansicht verschoben hat. Dann würde ich den bisherigen Inhalt des BufferedImages um die Anzahl der verschobenen Tiles verschieben und nur die neuen Tiles rendern. Damit stellst du sicher, dass nur das nötigste gerendert wird.
Falls du noch fragen hast, kannst du dich ja noch mal melden.


----------

