Welt möglichst effizient malen...

Major_Sauce

Bekanntes Mitglied
Hallöchen

Ich wollte mich mal der Herausforderung stellen, ein kleines Java-Game zu schreiben.
Und zwar sollte dies eine relativ "Abgespeckte" version von Teraria sein.
Ich habe nun 3 Anläufe gehabt, alle 3 gingen auch, aber ich hatte ständig performance Probleme.
Desswegen hätte ich hier ein paar Fragen :

1. Ich generiere bei jedem Start eine Welt, im Moment sollen das 100x100 Blöcke sein.
Diese Welt wird wie folgt generiert :
- Ich erstelle eine "Location", dies ist eine selbst geschriebene Klasse in der die X und Y Koordinate und ein Block, auch eine selbst geschriebene Klasse, gespeichert wird. In dieser Block Klasse wird ein BlockTyp gespeichert, im moment entweder Erde oder Luft, und dann noch einmal die dazugehörige Koordinate...
Diese "Location" sollte also nicht zu viel Speicher verbrauchen, da sie ja nur aus ein paar zahlen und anderen Variablen besteht.
Die ganzen Locations werden in einer HashMap gespeichert, um dann bei jedem repaint() die Location aus der HashMap zu holen, die der Spieler sehen kann. Leider wird das ganze aber extrem ruckelig. Ich kann teilweise zusehen, wie sich die Blöcke um einen Pixel verschieben, und das ganze obwohl ich weit über 60 mal in der Sekunde repainte. Sogar wenn ich am Ende des repaints gleich nochmal repainten lasse, was meiner Meinung nach dazu führen sollte, dass so oft repaintet wird wie nur möglich, ist es nicht ruckelfrei...

Den repaint führe ich auf einem JPanel aus, das auf einem JFrame liegt. Ich benutze die paintComponent() Methode, wobei mir leider immer noch niemand wirklich erklären konnte, wo der Unterschied zwischen paint() und paintComponent() liegt. In der Überschriebenen paintComponent() wird dann einfach die HashMap mit den ganzen Locations geladen, danach werden die benötigten Locations gesucht, es wird der BlockTyp abgefragt und dann das dazu passende Bild gemalt.

Gibt es da irgendwelche Möglichkeiten dies zu verschnellern, sollte ich in der paintComponent() vielleicht nicht rechnen, oder ist graphics2d.drawImage() ungeeignet ?
Hat da jemand ne Idee ?
Würde mich auf jeden Fall über eine schnelle Antwort freuen.

mfg Major_Sauce
 

Hestalon

Mitglied
Prinzipell würde ich sagen liegt an der HashMap.

Ich würde die "Locations" eher in nem 2D-Array speichern und da drüber laufen lassen.
Um nur genau die "Locations" zu bekommen die zu sehen sind den Mittelpunkt des Blickfelds merken und die Hälfte des Blickfelds drauf addieren/abziehen und die Werte als Start/End-Wert für das Rendern nutzen.

Sonst über Testausgaben die Funktionsaufrufe überprüfen wie lange die brauchen und so nach unten hangeln bis du den Übeltäter findest. Neben der Beschreibung die du gegeben hast könnte auch das jeweilige Stück Code helfen es zu verstehen.

Gruß
 

Major_Sauce

Bekanntes Mitglied
Hallo :)

Danke für die schnelle Antwort, habe gerade versucht die welt in kleine Teile zu zerstückeln, die dann nur noch 15x15 Blöcke beinhalten, was das ruckeln auch etwas eingeschränkt hat, aber es ist immer noch da.
Es hat sich mittlerweile jemand bei mir gemeldet, der gleich mal meinen Code anschaut.
Ich schreibe dann später mal ob wir das Problem gefunden haben, oder ob ich noch hilfe brauche.
Ach ja, das mit dem 2D-Array werde ich wohl gleich auch mal ausprobieren.

Danke :)

mfg Major
 

Thallius

Top Contributor
Das direkte Zeichnen in ein JPanel mit paintComponent ist sehr langsam. Da nutzt es auch nichts wenn du versuchst es 60x in der Sekunde zu machen. Das wird gar nicht klappen.

Du must zunächst in einen BufferedImage zeichnen und dann das fertige Image nur noch in das Panel mappen. Das sollte deutlich schneller sein.

Gruß

Claus
 

JCODA

Top Contributor
Das direkte Zeichnen in ein JPanel mit paintComponent ist sehr langsam. Da nutzt es auch nichts wenn du versuchst es 60x in der Sekunde zu machen. Das wird gar nicht klappen.

Du must zunächst in einen BufferedImage zeichnen und dann das fertige Image nur noch in das Panel mappen. Das sollte deutlich schneller sein.

Gruß

Claus

Quelle?

Edit: Ist ja nicht so, als müsste man dann 60x in der Sekunde dieses BufferedImage erzeugen ...
 
Zuletzt bearbeitet:

Major_Sauce

Bekanntes Mitglied
Also doch einfach aufs JPanel zeichnen ?
Ach ja, dank JCODA ist das Problem nun gelöst. Das problem war dass die Welt, dadurch dass ich bei jedem KeyEvent den Spieler um z.Bps einen Pixel verschoben habe. Da dieses KeyEvent aber nicht unbeding regälmäßig stattfindet, wurde die Welt hinter dem Spieler (sidescrolling) mal um einen, und mal um 2 oder sogar 3 pixel verschoben, was dann dazu führte dass es nciht flüssig lief.

So habe ich das Problem verstanden, bin mir aber nicht 100 % sicher.
Auf jeden Fall lief das ganze nach dem implementieren einer GameLoop, in der dann die Positionen berechnet wurden, schön flüssig.

mfg Major
 

Androbin

Bekanntes Mitglied
PS: "Double Buffering" ist bereits in Swing mit inbegriffen:

LEUTE!

hier wird g = getGraphics();

verwendet!

es wird die paint(Graphics g) von einem JFrame! überschrieben (und das ohne! super.paint(g) Aufruf!)

und ihr ratet ihm ehrlich zu Doublebuffering?! (das nebenbei in Swing AUTOMATISCH verhanden ist, wenn man Swing richtig benutzen würde...)

Tipp:

- überschreibe nicht die paint von einem Container, sondern nimm ein JPanel und überschreibe dort die paintComponent(..)
- benutze niemals getGraphics() auf einer Component!
- rufe jedesmal zuallererst die super-methode in einer paint()/paintComponent() auf.
- rufe nicht g.dispose(); in der von JFrame/JPanel paint/paintcomponent-Methoden auf.
 

Ähnliche Java Themen

Neue Themen


Oben