Suche

Home Infos/Tutorials PyGame Tilemap Tutorial 1
Tilemap Tutorial 1 PDF Drucken E-Mail
Geschrieben von: Matthias Meike   
Donnerstag, den 22. Juli 2010 um 06:49 Uhr

Tilemap Tutorial 1

Tilemap Screenshot

In diesem Tutorial lernt Ihr, wie man große Levels aus nur wenigen einzelnen Bildern erstellen kann.
Eine Tilemap wird sehr häufig in 2D-Spielen verwendet um größere Levels anhand von einzelnen "Kacheln" (Tiles) zusammen zu setzen. Dazu wird in der Praxis ein "Tileset" als Bild eingelesen, welches auch einzelnen aneinandergereihten Tiles gleicher Größe besteht. Die Einzelgrafiken werden dann einfach aus dem Basisbild heraus kopiert und in der gewünschten Reihenfolge zusammengefügt, so dass am Ende eine komplette Karte bzw. ein Level entsteht.
In diesem Beispiel wir der Schriftzug "Tile - Map" mit Hilfe von nur drei unterschiedlichen Einzelbildern (ein schwarzes, weißes und rotes Quadrat) auf den Bildschirm gezeichnet.
Mit dieser Methode lassen sich leicht komplexe Level "zusammen puzzlen" und dabei auch noch den Grafikspeicher schonen.

Dieses erste Tutorial soll Euch das grundlegende Prinzip zeigen, welches hinter Tilemaps steckt. Der Code wurde absichtlich einfach gehalten und ist für den Produktiveinsatz nur bedingt geeignet da die Performance durch die vielen Einzelblittings bei jedem Schleifendurchlauf bei größeren Karten stark in den Keller gehen dürfte. Im Normalfall würde man ein solche Karte nur einmal rendern und anschließend nur noch die Bereiche aktualisieren, welche sich im Laufe des Spiels verändern.
Keine Sorge, im laufe dieser Tutorialreihe werdet Ihr noch lernen wie man "Alltagstaugliche" Tilemaps erstellt. Wink
Ich habe in diesem Beispiel auf das laden von Bildern verzichtet und verwende als Tiles hart codierte quadratische Surfaces. Dadurch könnt Ihr den Code einfach per Copy-Paste kopieren und sofort ausführen.
Wenn ihr ein wenig mit dem Code experimentieren wollt, versucht doch einmal die einfarbigen Surfaces durch Bilder zu ersetzen.


Ein einfaches Tilemap Beispiel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import pygame
from pygame.locals import *
 
def create_tilemap():
"""
Erzeugt eine 2-dimensionale Karte (Tilemap), bestehend
aus verschachtelten Listen.
"""
map = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,1,1,1,0,2,0,0,1,0,0,0,1,1,1,0,0,0,0,0,1],
[1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1],
[1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,1,1,0,1,1,1,0,1],
[1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1],
[1,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1],
[1,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1],
[1,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,1,1,1,0,0,0,1],
[1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,0,1,0,0,0,0,0,1],
[1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
return map
 
def render_tilemap(tmap):
"""
Erzeugt aus den Informationen der Tilemap ein visuelles
Abbild als Surface.
"""
tilesize = 20
map_x = len(tmap[0])
map_y = len(tmap)
map = pygame.surface.Surface((map_x*tilesize,map_y*tilesize))
for x in range(map_x):
for y in range(map_y):
tile = pygame.surface.Surface((tilesize,tilesize))
if tmap[y][x] == 0:
tile.fill((0,0,0))
elif tmap[y][x] == 1:
tile.fill((255,255,255))
elif tmap[y][x] == 2:
tile.fill((255,0,0))
 
map.blit(tile,(x * tilesize,y * tilesize))
 
return map
 
resolution = (800,600)
bgcolor = (0,0,0)
 
pygame.init()
 
screen = pygame.display.set_mode(resolution)
pygame.display.set_caption("Tilemap Demo")
 
timer = pygame.time.Clock()
running = True
 
tilemap = create_tilemap()
 
while running:
timer.tick(30)
 
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
 
 
screen.fill(bgcolor)
screen.blit(render_tilemap(tilemap),(0,0))
 
pygame.display.flip()
 

Schritt für Schritt

Das Meiste sollte euch eigentlich schon bekannt vorkommen wenn ihr das Tutorial "Erste Schritte in PyGame" gelesen habt.

Das PyGame Fenster wird initialisiert und in einer per Frametimer gedrosselten Schleife alle aufgetretenden Events abgefangen.

Kernpunkte dieses Tutorials sind die beiden Funktionen "create_tilemap" und "render_tilemap".

 

create_tilemap

Diese Funktion erstellt eine verschachtelte Liste, welche definiert an welcher Stelle welches einzelne Tile auf den Bildschirm gezeichnet werden soll. Diese zweidimensionale Karte kann wunderbar über zwei verschachtelte for-Schleifen durchlaufen werden, wie es die Funktion "render_tilemap" beweist.

Eine einfache 2D Karte lässt sich auf diese Weise noch relativ übersichtlich per Hand generieren. Häufig werden in Spielen allerdings mehrere Ebenen (Layer) verwendet um z.B. Objekte darstellen zu können, welche andere Objekte verdecken. Eine solche Karte "per Hand" zu erstellen nimmt einem allerdings komplett die Übersicht und ihr solltet dafür lieber einen Karteneditor verwenden.

render_tilemap

Diese Funktion zeichnet die Karte anhand des zuvor erstellten Modells auf ein Surface und liefert selbiges als Rückgabewert zurück.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def render_tilemap(tmap):
"""
Erzeugt aus den Informationen der Tilemap ein visuelles
Abbild als Surface.
"""
tilesize = 20
map_x = len(tmap[0])
map_y = len(tmap)
map = pygame.surface.Surface((map_x*tilesize,map_y*tilesize))
for x in range(map_x):
for y in range(map_y):
tile = pygame.surface.Surface((tilesize,tilesize))
if tmap[y][x] == 0:
tile.fill((0,0,0))
elif tmap[y][x] == 1:
tile.fill((255,255,255))
elif tmap[y][x] == 2:
tile.fill((255,0,0))
 
map.blit(tile,(x * tilesize,y * tilesize))
 
return map

Zunächst wird über die Variable "tilesize" die größe der einzelenen quadratischen Tiles definiert.

Anschließend werden die Dimensionen der Karte auf der x bzw. y-Achse ermittelt, sprich wie viele Tiles werden horizontal / vertikal gezeichnet.
len(map[0]) gibt die Anzahl an Listeneinträgen der ersten Verschachtelten Liste zurück (x-Achse).
len(map) liefert die Gesamtzahl an Verschachtelten Listen zurück, welches dem Wert der y-Achse entspricht.
map_x = len(map[0])
map_y = len(map)
Als nächstes wird das temporäre Surface "map" mit den endgültigen Dimensionen der Karte erstellt, auf welches später die einzelnen Tiles gezeichnet werden.
map = pygame.surface.Surface((map_x*tilesize,map_y*tilesize))
Nun wird die Liste "tmap" spalten- und zeilenweise durchgelaufen und für jeden einzelnen aus (x/y) definierten Punkt ein quadratisches Tile-Surface generiert.
tile = pygame.surface.Surface((tilesize,tilesize))
Im Beispiel wurden für die einzelnen Punkte Werte von 0-2 vergeben, aus welchen nun über die Anweisung "tile.fill" unterschiedlich farbige Kästchen generiert werden.
Diese werden schließlich per "map.blit" an der in der Tilemap festgelegten Position in das temporäre Karten-Surface eingezeichnet.
map.blit(tile,(x * tilesize,y * tilesize))
Wenn das temporäre Surface vollständig "bemalt" wurde, wird dieses von der Funktion zurückgegeben und per "screen.blit" in die obere linke Ecke (0,0) des Screen-Surface projiziert.

Die methode surface.blit malt das als Parameter übergebene Surface an die als Tuple angegebene Position des Surface, welches die Methode "blit" aufruft.














t
Zuletzt aktualisiert am Sonntag, den 13. März 2011 um 18:37 Uhr
 
     © Matthias Meike - LaymaXx.de
CSS ist valide!