I think @gurbuz's answer covered most of this already, so I will present much the same answer, but with my own spin ;)
So your TMX map defines a grid of textured-tiles which make up a screen full of map/level/whatever. Just like ceramic floor tiles, they are each handled individually, and placed on the floor individually.
The code in the question looks correct to find the (0,0 / upper-left) single tile in layer zero of the map and draw it to the screen. I suspect it's producing an error for layer=1
because the map only contains one layer. But without the map, it's impossible to know.
To show the entire map, it's necessary to loop over every tile defined in the .tmx
file, and place them onto a surface. This surface can then be simply .blit
~ted to the pygame window.
I cobbled together this basic function which loads the entire map, rendering it to a surface. This is a naïve way to do it, because this image could be huge. But it serves the purpose of illustrating how to traverse the elements of the map and draw them.
# Convert HTML-like colour hex-code to integer triple tuple
# E.g.: "#892da0" -> ( 137, 45, 160 )
def hexToColour( hash_colour ):
red = int( hash_colour[1:3], 16 )
green = int( hash_colour[3:5], 16 )
blue = int( hash_colour[5:7], 16 )
return ( red, green, blue )
# Given a loaded pytmx map, create a single image which holds a
# rendered version of the whole map.
def renderWholeTMXMapToSurface( tmx_map ):
width = tmx_map.tilewidth * tmx_map.width
height = tmx_map.tileheight * tmx_map.height
# This surface could be huge
surface = pygame.Surface( ( width, height ) )
# Some maps define a base-colour, if so, fill the background with it
if ( tmx_map.background_color ):
colour = tmx_map.background_color
if ( type( colour ) == str and colour[0].startswith( '#' ) ):
colour = hexToColour( colour )
surface.fill( colour )
else:
print( "ERROR: Background-colour of [" + str( colour ) + "] not handled" )
# For every layer defined in the map
for layer in tmx_map.visible_layers:
# if the Layer is a grid of tiles
if ( isinstance( layer, pytmx.TiledTileLayer ) ):
for x, y, gid in layer:
tile_bitmap = tmx_map.get_tile_image_by_gid(gid)
if ( tile_bitmap ):
surface.blit( tile_bitmap, ( x * tmx_map.tilewidth, y * tmx_map.tileheight ) )
# if the Layer is a big(?) image
elif ( isinstance( layer, pytmx.TiledImageLayer ) ):
image = get_tile_image_by_gid( layer.gid )
if ( image ):
surface.blit( image, ( 0, 0 ) )
# Layer is a tiled group (woah!)
elif ( isinstance( layer, pytmx.TiledObjectGroup ) ):
print( "ERROR: Object Group not handled" )
return surface
So once the map is "converted" to a surface, it's possible to simply blit this surface onto the pygame screen:
# Before the main loop starts
tmx_map = pytmx.load_pygame( "test.tmx", pixelalpha=True )
map_image = renderWholeTMXMapToSurface( tmx_map )
# Main loop
while not finished:
...
pygame_screen.blit( map_image, ( 0, 0 ) )
...
A better way of doing this would be to only load the elements of the TMX map necessary for display. It's easy to record which sub-co-ordinates of the map are displayed, and then go generate - say the right-side column when this needs to come into view.