# Tilemap, aber wie? (Ein Konzept)



## MarcoBehnke (24. Aug 2007)

Status quo ist, dass ich für mein Spiel die komplette Karte als ein Bild vorliegen habe.
Per


```
g2d.drawImage(
  background.getImage(),
  0, 0, getScreenWidth() - 1, getScreenHeight() - 1,
  (int) offset_x,
  (int) offset_y,
  getScreenWidth() - 1 + (int) offset_x,
  getScreenHeight() - 1	+ (int) offset_y,
  this
);
```

zeichne ich dann den jeweils sichtbaren Bereich (scrollende Map).

Das ist natürlich Müll. Weiterführend möchte ich natürlich meine MAP dynamisch laden.

Dazu habe ich mir überlegt, dass ich mir eine Klasse Tilemap anlege, der ich die Struktur meiner Map übergebe


```
protected Image[][] tiles;
public TileMap(int width, int height);
public loadTile(String imageName, int x, int y, int width, int height)
public Image getMap(x, y, width, height);
```

In meine Spieleklasse würde ich dann äquivalent zu oben wie folgt aufrufen:

int map_x = (int) offset_x;
int map_y = (int) offset_y;
int map_width = getScreenWidth() - 1 + (int) offset_x;
int map_height = getScreenHeight() - 1 + (int) offset_y;
g2d.drawImage(
  tileMap.getMap(map_x, map_y, map_width, map_height),
  0, 0, getScreenWidth() - 1, getScreenHeight() - 1,
  this
);[/code]

So viel zur Struktur.
In getMap wird ermittelt, welche Tiles im Sichtbereich liegen. Alle Images, die noch nicht in Image[][] tiles vorhanden sind, müssen nachgeladen werden.

Dann muss ich (und hier weiß ich nicht wie man das macht), die relevanten Tiles zu einem Image zusammenkopieren und den daraus relaventen Bereich ermitteln (es kann ja sein, dass einige Tiles nicht ganz zu sehen sind) und ausliefern. Um etwas zu cachen, würde ich mir das gebaute Image solange vorhalten, wie immer wieder die selben Tiles angefragt werden, dann muss ich nur entsprechend einen anderen Ausschnitt zurückliefern.

Um Speicher frei zu machen, würde ich mir auch merken, welche Images in Image[][] tiles seit Zeit x nicht mehr angefragt wurden und entsprechend aus dem Array entfernen.

*Frage 1:* Wie ich Images lade weiß ich, wie ich ein Image einer bestimmten Größe erstelle ebenfalls, aber wie kopiere ich nun Einzelbilder zu einem großen zusammen?

*Frage 2:* Bevor ich mir einen Algorithmus überlege, hat vielleicht jemand für mich einen Hinweis, wie ich an Hand der Tilegröße und des angefragten x,y,width,height Bereiches aus meiner Tilemap die richtigen Bilder ermittel?


Beispielmap (Tilegröße 32 Pixel)
1 : 1 : Bild 1 (0,0,31,31)
1 : 2 : Bild 2 (32,0,63,31)
1 : 3 : Bild 3 (64,0,95,31)
2 : 1 : Bild 4 usw.
2 : 2 : Bild 5
2 : 3 : Bild 6
3 : 1 : Bild 7
3 : 2 : Bild 8
3 : 3 : Bild 9

getMap(33, 2, 40, 40) würde dann entsprechend zu den Bildern (1:2), (1:3), (2:2), (2:3) passen.


Oder ist mein Konzept vielleicht total beknackt?


----------



## Steev_Ly-Ling (12. Sep 2007)

Was ist daran beknackt?
Allerdings würde ich die Map nicht wärend der Laufzeit auseinanderschneiden sondern dies vor der Laufzeit machen und dann als Map nur noch einen 2d Integer-Array und einen 1d Image-Array anlegen. Der Integer-Array zeigt dann die Nummer des Bildes an einer bestimmten Position und der Image-Array enthält die Bilder.

Ich denke nämlich das es zu viel Rechenzeit kostet die Map währen der Laufzeit in Stücke zu zerhacken.
1.) Wird der Prozess spätestens bei einer Mapgröße von 2000x2000px in die Knie gehen und zweitens kann man mit dieser (s.o.) Art von Stückbasierten Leveln viel größere Welten erstellen (GTA).


----------



## MarcoBehnke (12. Sep 2007)

ach so, nee, so hatte ich das auch gedacht  deswegen die loadTile Funktion die die einzelnen Mapteile lädt.


----------



## Quaxli (18. Sep 2007)

Ein Tipp von mir zum Aufbau einer Map. Ich habe mal eine Lösung gebastelt, die mir immer noch gut gefällt, vor allem hatte ich trotz großer Karte keine Probleme:

- Ich habe eine Klasse zur Verwaltung der Bilder gebastelt und dort alle initial geladen, numeriert und gespeichert. 
- Zusätzlich habe ich mir eine Klasse Tile gebaut, die hauptsächlich von Rectangle erbt und ein paar Zusatz-Informationen enthält, wie z. B. die Nummer des Bildes (0 = Gras)
- Die Verwaltung der Tiles übernimmt eine weitere Klasse. Ich hatte damals eine Collection anstelle eines Arrays verwendet, aber das hat mehr mit persönlichen Vorlieben zu tun.
- Die Tiles erhalten, da sie von Rectangle erben, Positionswerte, wobei das Tile links oben 0/0 hat
- Ich habe mir eine imaginäre Klasse Screen gebaut, die die aktuell Bildschirmposition beinhaltet. Wenn sich der Spieler nun bewegen soll, verändere ich die Position der Klasse Screen. Auch Screen erbt bei mir von Rectangle...

Beim Zeichnen geschieht folgendes:
- Ich übergebe die Klasse Screen bzw. deren Position an die Tile-Verwalterklasse. Diese loopt in der paint-Methode über alle Tiles und prüft, ob diese sich mit Screen überschneiden (Rectangle.intersects(..)).
- alle Tiles, die sich mit Screen überschneiden, werden auf den Bildschirm gezeichnet. Dazu rufe ich die paint-Methode der Klasse Tile auf.
- Für dies Tiles wird die Screen-Position von der TilePositon subtrahiert. Somit werden auch Tiles richtig gezeichnet, die nur teilweise sichtbar sind.
- Die Tiles holen sich zum Zeichnen die Bilder aus der Klasse, welche die tatsächlichen Bilder verwaltet.


----------



## MarcoBehnke (18. Sep 2007)

Die Idee mit dem intersects ist klasse ! Danke.


----------

