# Scrollen im Full-Screen Exclusive Mode



## Bastler (1. Mai 2010)

Hallo,

ein paar Freunde und ich sind grad dabei ein Spiel zu programmieren.
Angefangen haben wir es als Swing-Applikation, welche einen JViewport zum scrollen auf der "Weltkarte" enthielt.
Nun wollten wir es eigentlich als Vollbild-Anwendung umbauen, und haben uns zu diesem Zweck das Sun Tutorial zum Full-Screen Exclusive Mode durchgelesen.
Da das scrollen per Pfeiltasten, Swing-Timer und JViewport.setViewPosition(...) seeehr langsam war, habe ich mich sehr darüber gefreut, dass der Full-Screen Exclusive Mode sehr viel mehr Performance bieten soll, allerdings haben wir keinen Weg gefunden den JViewport darunter weiter zu benutzen, da er auf repaint() angewiesen zu sein scheint.

Gibt es einen Weg den JViewport auch unter dem Full-Screen Exclusive Mode effektiv zu nutzen, oder habt Ihr eine Idee wie man das Scrollen auf letztendlich einem recht großem Bild unter Full-Screen Exclusive Mode performance-sparend realisieren kann?

Achja, wir haben uns noch gefragt, welche Anzahl bei createBufferStrategy(x) sinnvoll ist. Auf meinem Rechner funktioniert es imho nur bei 1, obwohl bei eigentlich allen Beispielen 2 verwendet werden.
Bei mehr als einem Buffer wird bei mir immer ein schwarzer Bildschirm angezeigt.
Ich habe getBufferCapabilities() vom GraphicsConfiguration aufgerufen und auf die verschiedenen Capabilities untersucht, und es wird scheints alles (auch Multi-Buffering) unterstützt.
Allerdings bin ich ein ziemlicher Neuling auf dem Gebiet und kann mit diesen ganzen Infos nicht viel Anfangen.
Falls mir da also jemand auf die Sprünge helfen könnte, wäre dies sehr freundlich =).

Grüße vom Bastler


----------



## Steev (2. Mai 2010)

Ich würde nicht die Standard-Swing-Komponenten verwenden sondern etwas eigenes bauen und das verwenden. Wenn ich dich richtig verstanden habe, dann soll eine Map gescrollt werden. Ich würde dafür eine Tilemap verwenden, die ich über die Pfeiltasten entsprechend steuern kann.

Hier mal eine kleine Anregung:
SourceForge.net Repository - [rpgenesis] Index of /trunk/src/RPGenesis/com/rpgenesis/graphic2D/map

Gruß
Steev


----------



## Bastler (2. Mai 2010)

Vielen Dank für die Idee, die Tilemap kannte ich noch gar nicht und werde es mir mal anschauen =).

Gruß vom Bastler

€: Ok, ich habe mir das Prinzip mal angeschaut, und es sieht eigentlich dem sehr ähnlich was wir gemacht haben.
Unsere Map besteht ebenfalls aus einem 2D-Array vieler kleinerer Felder, welche jeweils aus einem "Terrain"-Image bestehen.

Da sich das Terrain im Normalfall nicht ändert, haben wir, um "Performance zu sparen", die gesamte Map in ein Offscreen-Image gezeichnet, sodass hinterher nur noch Ausschnitte dieses einen Bildes gezeichnet werden müssen, statt dass immer wieder das Array durchgegangen werden muss um die einzelnen Terrain-Images zusammen zu suchen und daraus die Map immer wieder neu gepuzzelt werden muss. (Scheints war das eher eine unsinnige Idee ;()

Das Problem beim Vollbildmodus ist nun: Wie sorgt man dafür, dass wirklich nur das nötigste gezeichnet wird?
Wir haben es mit getSubimage() versucht, jedoch scheint das Erstellen dieses Subimages viel mehr zu verzögern, als das Zeichnen von nicht sichtbaren Bereichen.

Ich werde mal Versuchen das Erstellen das gesamten Map-Images wieder wegzulassen, und beim Scrollen stattdessen wieder das auf das Terrain-Array zuzugreifen. Damit ist es jedenfalls sehr einfach, nur die Bereiche neu zu zeichnen, die auch wirklich neu gezeichnet werden sollen.


----------



## Steev (2. Mai 2010)

Hi,

um das Problem eures Ansatzes zu verstehen muss man etwas in den "internen" Java-Code gucken. getSubimage erzeugt immer ein neues Image-Objekt und alloziiert damit eine Menge Heap-speicher. Da ihr diese Methode so etwa 60-100 Mal pro Sekunde aufruft und dabei jedesmal das vorherige Image-Objekt verwerft ist der Heap-Speicher innerhalb von Null Komma Nichts zugemüllt und der Garbage-Collector muss die ganzen "toten" Instanzen erstmal aufräumen.
Wenn man stattdessen nur den sichtbaren Mapausschnitt rendert dann sind das vieleicht 10 Bilder, die gerendert werden müssen, das ist auf jedem Fall schneller.

In dem SF-Projekt hast du sicher gesehen, dass dort als "Viewport" eine Camera-Klasse verwendet wird. Der sichtbare Bereich wird dabei wie folgt berechnet:


```
public void calculateTilesToRender(Camera camera) {
        int vx = (int) (camera.getX() - getX());
        int vy = (int) (camera.getY() - getY());
        int vw = camera.getWidth();
        int vh = camera.getHeight();

        // Berechne, wie viele Tiles gerendert werden müssen
        int twh = tileSize;
        int vtx = vx / twh;
        int vty = vy / twh;
        int vtw = (vw / twh) + (vw % twh != 0 ? 1 : 0);
        int vth = (vh / twh) + (vh % twh != 0 ? 1 : 0);

        ttr.x = vtx;
        ttr.y = vty;
        ttr.width = vtw;
        ttr.height = vth;

        ttr.width = ttr.x < 0 ? ttr.width + ttr.x : ttr.width;
        ttr.height = ttr.y < 0 ? ttr.height + ttr.y : ttr.height;
        ttr.x = ttr.x < 0 ? 0 : ttr.x;
        ttr.y = ttr.y < 0 ? 0 : ttr.y;
    }
```

Ok, der Code ist etwas suboptimal, aber im Grunde genommen wird nur die Kameraposition auf der Map sowie die Größe des Bildausschnitts in Tiles umgerechnet und diese als "Viewport" verwendet.

Gruß
Steev


----------

