# schnellste alternative um in java zu "zeichnen"



## Java Chris (1. Jul 2006)

würd gern ein isometric spiel machen, dazu bräuchte ich aber ne gewisse geschwindigkeit um die Landkarte schön und schnell darzustellen, was gibts denn da in java an schnelles?

ich kenn in java nur swing und awt um etwas darzustellen, gibts was besseres bzw schnelleres?


----------



## Wildcard (1. Jul 2006)

Mit SWT(externe Bibliothek) kannst du mit Betriebssystem-Resourcen zeichnen.


----------



## AlArenal (1. Jul 2006)

Es gibt diverse Schnittstellen zu OpenGL, wie z.B. JOGL. In der Regel heißt es aber:

1. make it work
2. make it fast

Hast du empirische Daten (Test-Code), die deine Vermutung stützen, dass AWT/Swing alleine nicht reichen?


----------



## Beni (1. Jul 2006)

Du könntest auch OpenGL benutzen (z.B. mit JOGL). Da könntest du vielleicht auch einige Dinge, wie die Berechnung Vorder-/Hintergrund, an die Hardware abgeben.

[Edit, grrr, zu langsam]


----------



## 0xdeadbeef (1. Jul 2006)

Es gibt Sachen, die sind in Swing/AWT lahm. Das blitten von Grafiken in ein Graphics(2D)-Objekt geht aber sehr flott, solange man BufferedImages benutzt.


----------



## Java Chris (1. Jul 2006)

naja ich hab nur versucht 100x100 felder darzustellen und das hat schon ewig gedauert, inklusive um 45° drehung

sonst bin ich eigentlich auch ein feind von leuten, die sagen, java sei langsam


----------



## Java Chris (1. Jul 2006)

bzw wenn ich jogl für sowas verwenden kann, kann ich auch lwjgl verwenden or?


----------



## Beni (1. Jul 2006)

Ja, ist ja beides fast dasselbe.


----------



## 0xdeadbeef (2. Jul 2006)

Java Chris hat gesagt.:
			
		

> naja ich hab nur versucht 100x100 felder darzustellen und das hat schon ewig gedauert, inklusive um 45° drehung
> 
> sonst bin ich eigentlich auch ein feind von leuten, die sagen, java sei langsam



Willst Du die Felder in "Echtzeit" drehen? Warum legst Du die Grafiken nicht gleich "richtig" ab oder drehst sie zumindest nur einmal beim Start des Spiels?
Und 100x100 Felder sind 10000 Felder. Kaum vorstellbar, daß die auf einmal auf den Bildschirm passen. Also zeichne entweder nur die, die auch wirklich zu sehen sind oder mal sie in eine große Hintergrundgrafik und kopier dann den Teil raus, der zu sehen ist.
Und nur am Rande: Java benutzt - soweit möglich - Hardwarebeschleunigung, wenn man BufferedImages benutzt (am besten mit GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage() erzeugen).
Ich bezweifle ganz entschieden, daß Du mit JOGL und dergleichen ernsthaft schneller wirst.


----------



## Java Chris (3. Jul 2006)

0xdeadbeef hat gesagt.:
			
		

> GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage()



hört sich interessant an, hab ich noch nie verwendet, muss ich dann mal ausprobieren


----------



## 0xdeadbeef (3. Jul 2006)

Eigentlich werden BufferedImages immer hardwarebeschleunigt, falls es irgendwie geht. Die per CreateCompatibleImage erzeugten Bilder sind aber von einem Typ, der auf diesem System auf jeden Fall optimal wiedergegeben werden kann - wenn Hardwarebeschleunigung überhaupt verfügbar ist.

Falls Du Fullscreen benutzt, wäre auch ein 16bit-Modus überlegenswert. Auf ollen Rechnern ist ein 16bit-Fullscreen-Modus teils dramatisch flotter als ein 32bit-Modus.

Trotzdem denke ich, daß Du eventuell Deinen Zeichenalgorithmus überdenken solltest. Falls Du wirklich 10000 Bilder pro Frame um 45° drehst und zeichnest, wirst Du so oder so auf keinen grünen Zweig kommen.
Wenn's auf Zeichenperformance ankommt, sollte man folgende Dinge beachten:
1) Alles, was irgendwie geht, vor dem eigentlichen Spiel/Level berechnen, zeichnen und cachen.
2) Während des Spiels nur das zeichnen, was unbedingt benötigt wird. Jeden Pixel nach Möglichkeit nur einmal zeichnen.

Bei einem scrollenden Spielfeld (gehe ich jetzt mal davon aus), gibt es prinzipiell zwei Ansätze: 
1) Vorher den gesamten statischen Level in ein großes Graphics-Objekt malen und dann bei jedem Frame den passenden Teil aus der Hintergrundgrafik kopieren. Darüber dann animierte Objekte malen.
2) Statisches Spielfeld aus Kacheln/Tiles aufgebaut: für jeden Frame bestimmen, welche Tiles sichtbar sind und dann genau diese Kacheln zeichnen. Darüber dann wieder animierte Objekte malen.

#1 ist nur bis zu einer gewissen Größe sinnvoll, aber einfacher zu implementieren und flexibler, weil der Level auf beliebigen Objekten aufgebaut sein kann.
#2 ist das Standardverfahren für typische 80er/90er-Konsolenspiele. Mit symmetrischen Tiles recht gut beherrschbar für fast beliebige Levelgrößen. Levelbau ist sehr einfach (z.B. ASCII-Zeichen in Textdatei). Nachteil: etwas mehr Aufwand als #1 und nicht trivial für unsymmetrische Tiles.


----------



## DEvent (15. Jul 2006)

> GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage()


noch länger gehts kaum noch   
sorry 4 OT


----------



## Moonlight1234 (15. Jul 2006)

Ich habe beides mal ausprobiert:



> 1) Vorher den gesamten statischen Level in ein großes Graphics-Objekt malen und dann bei jedem Frame den passenden Teil aus der Hintergrundgrafik kopieren. Darüber dann animierte Objekte malen.
> 2) Statisches Spielfeld aus Kacheln/Tiles aufgebaut: für jeden Frame bestimmen, welche Tiles sichtbar sind und dann genau diese Kacheln zeichnen. Darüber dann wieder animierte Objekte malen.



Methode 1:
Ichhabe den gesammten Level als statische Image (mit 

```
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration().createCompatibleImage() )
```
gezeichnet.
Der aktuell dargestellte Ausschnitt wird in eine Volatile Image kopiert und dann ins Frame kopiert
Ich erreiche dadurch Frameraten von 270 Frame/sec.
Ich bin immer davon aus gegangen das dieses die schnellste Methode ist, da ja alles vorgezeichnet ist und nur noch kopiert wird. Speicherplatzintensiv aber schnell.

Ich habe trotzdem nochmal Methode 2 ausprobiert:
Die Tiles habe ich als statische Image angelegt.
Die werden dann immer wieder neu in eine Volantile Image gezeichnet.
Die Volantile Image wird dann ins Frame kopiert.
Ich erreiche dabei Frameraten von etwa 500 Frames/sec.

Ich hatte eigentlich angenommen das dieses die langsamste Methode ist, da ja alles immer wieder neu gezeichnet wird.

Weiß jemand erklären wie diese unterschiedliche Geschwindigkeit zu Stande kommt?

Außerdem habe ich bei Methode 2 das Problem daß bei einem minimieren des Spieles mit ALT-TAB  die Framerate, dh. Die Leistung der volatile Image sinkt und so niedrig bleibt, auch wenn ich wieder in das Spiel gehe.
Selbst wenn ich die Volantile Image neu erzeuge bleibt die Framerate niedrig.
Welche Einstellungen muß ich neu setzen wenn ich wieder die hohe Framerate habe will?
volantileImage.setPriority(1.0F)
und ein erneutes setzten des Frame im GraphicsDevice mit
 setFullScreenWindow()
brachte keine Änderung.

Gruß, Moonlight1234


----------



## 0xdeadbeef (16. Jul 2006)

Ein "volatile" Image _muß_ nicht im Speicher der Grafikkarte liegen, es _kann_ da liegen. Ein Problem ist zudem, daß sie halt im wahrsten Sinne des Wortes "flüchtig" sind. Schlimmstenfalls kann es passieren, daß das Image überschrieben wird und man es neu zeichnen muß. Dafür gibt es ja auch einen Listener-Mechanismus, soweit ich mich erinnere.
Ich könnte mir vorstellen, daß Dir sowas passiert, also daß durch das Umschalten die Grafikkarte den Speicher für sich reklamiert und das volatile Image ausgelagert wird.
Wenn ich das richtig kapiert habe, werden managed Images (also solche, die man per CreateCompatibleImage) erzeugt hat, ebenfalls im Speicher der Grafikkarte gehalten, wenn es denn möglich ist. Ich persönlich schlage mich deshalb auch gar nicht mit volatile Images rum.

Was das Reinkopieren der "großen" Grafik angeht: wie machst Du das denn? Kopierst Du wirklich nur den benötigten Ausschnitt oder vertraust Du aufs Clipping? Ansonsten könnte es natürlich sein, daß das große Image im Speicher der Grafikkarte liegt (ist ja "managed") und dadurch andere Sachen (z.B. der Frambuffer) keinen Platz mehr finden.
Es kann aber auch gut sein, daß das Kopieren eines Image-Ausschnitts nicht (komplett) hardwarebeschleunigt ist, daß Kopieren eines kompletten Images aber schon. Eventuell gibt es auch eine Größenlimitierung für die Hardwarebeschleunigung.[/i]


----------



## Moonlight1234 (17. Jul 2006)

Den Status der VolatileImage prüfe ich permanent.
Es werden bei beiden Methoden statische Images in eine Volatile Image kopiert.
Der Unterschied ist nur die Größe der statishen Image . Ich kopiere den Ausschnitt aus der großen Grafik mit drawImage.
Clipping wäre ein Ansatz den ich mir nochmal anschauen könnte.
Wobei ich auch bei kleinen Levelgrößen (1024x768) genau die gleiche Framerate wie oben angeben habe.
Ich werde wohl (erstmal) Methode 2 verwenden, da diese anscheinend schneller ist, vom geringeren Speicherplatzbedarf mal abgesehen.
Längerfristig könnte es damit aber Probleme geben. 
Im Moment verwende ich nur wenige verschiedene Tiles. Wenn ich mehr unterschiedliche Tiles verwende, wird der Speicherplatzbedarf größer. Dann könnte die Performace von Methode 2 sinken.  Momentan sind die Tiles alle gleich groß. Mittelfristig will ich evtl. unterscheidlich große Tiles, welche nicht an einem Raster ausgerichtet sind verwenden.
Dann wird es komplizierter, wenn man nur den jeweils sichtbaren Levelausschnitt neu zeichnen will.
Ich müßte dann für jedes Tile prüfen ob es gerade sichbar ist, was eine Menge Performance kosten wird.

Leider kann man aus dem Source von von createCompatibleImage() und createVolatileImage() nichts lesen, da diese nativ implementiert sind.
Schade.


----------



## Memphis (19. Jul 2006)

Moonlight1234 kannste mal zentrale Punkte deiner Engine posten - also nen bissel Code. Da ich auch gerade ein Isometricspiel entwickle und ich komm nur so auf 50 Fps. Wenn es möglich wäre vll. wie du die Images erzeugst, dann vll. noch den renderalgo und so vll. noch nen bissel mehr.

Memphis verdankt sich für alles was kommt.


----------



## 0xdeadbeef (19. Jul 2006)

Bei unterschiedlichen PCs und unbekannter Bildschirmauflösung (bzw. Größe des angezeigten Fensters) ist ein Vergleich der Framerate kaum sinnvoll, oder?


----------



## Moonlight1234 (19. Jul 2006)

> Moonlight1234 kannste mal zentrale Punkte deiner Engine posten - also nen bissel Code. Da ich auch gerade ein Isometricspiel entwickle und ich komm nur so auf 50 Fps. Wenn es möglich wäre vll. wie du die Images erzeugst, dann vll. noch den renderalgo und so vll. noch nen bissel mehr.



Das Programm ist mittlerweile so umfangreich daß ich den Code nicht mehr posten kann, daß würde nichts bringen.
Das brauchst du auch nicht.
Erzeuge die Image wie von 0xdeadbeef  vorgeschlagen mit createCompatibleImage().
Schaue dir außerdem auch mal  BufferStrategy an. VolatileImage braucht man erst mal nicht, bzw wenn du BufferStrategy verwendest dann kannst du auf VolatileImage ganz verzichten.
Was von beidem man verwendet ist eher Geschmackssache.

In einem anderen Topic hatten mir 0xdeadbeef und andere sehr geholfen:
http://www.java-forum.org/de/viewtopic.php?t=20670&highlight=scrolling



> Bei unterschiedlichen PCs und unbekannter Bildschirmauflösung (bzw. Größe des angezeigten Fensters) ist ein Vergleich der Framerate kaum sinnvoll, oder?



Das stimmt.
Die Framerate von 500 Frames/sec ist ohnehin unter idealen Vorausetzungen gemessen. Sobald bestimmte Ereignisse auftreten (Sound, Kollisionsabfrage etc.) schwankt diese sehr.
Ich wollte auch nur darauf hinweisen das der Unterschied zwischen 270 und 500 Frames/sec erheblich ist.
Wobei auch eine Framerate von 270 Frames/sec mehr als aussreichen wäre.
Ich probiere nur mal ganz gerne was anderes aus.


----------

