Reputation: 109
I have made a *tmx map in the Tiled Editor program. Then I tried to import it into my game. When I change the variable layers
to 0
it works, but there is only 1 tile on the screen. I want to print the entire map on my screen. But I get the following error.
Traceback (most recent call last):
File "C:\Users\LL\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pytmx\pytmx.py", line 512, in get_tile_image
layer = self.layers[layer]
IndexError: list index out of range
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\LL\Desktop\Erik\RPG_project\RPG project\data\main.py", line 143, in <module>
game_initialize()
File "C:\Users\LL\Desktop\Erik\RPG_project\RPG project\data\main.py", line 117, in game_initialize
map_setup()
File "C:\Users\LL\Desktop\Erik\RPG_project\RPG project\data\main.py", line 140, in map_setup
image = tmxdata.get_tile_image(0, 0, 2)
File "C:\Users\LL\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pytmx\pytmx.py", line 514, in get_tile_image
raise ValueError
ValueError
I think it has to do with my layers. I have only 1 layer for my map. Still my script doesnt work. I also use Base64 (compressed) for my map. And 32 pixels large tiles.
from pytmx import load_pygame
def map_setup():
global image
# Getting / Importing the map
tmxdata = load_pygame("Tile_files\\mymap2.tmx")
image = tmxdata.get_tile_image(0, 0, 1) # x, y, layer
Upvotes: 2
Views: 4137
Reputation: 14924
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.
Upvotes: 2
Reputation: 351
Because tile seems only (0,0) position. You have to gave loops the layers. I wrote this code maybe help you.
from pytmx import load_pygame, TiledTileLayer
def map_setup():
global image
# Getting / Importing the map
tmxdata = load_pygame("Tile_files\\mymap2.tmx")
width = tmxdata.width * tmxdata.tilewidth
height = tmxdata.height * tmxdata.tileheight
ti = tmxdata.get_tile_image_by_gid
for layer in tmxdata.visible_layers:
if isinstance(layer, TiledTileLayer):
for x, y, gid, in layer:
tile = ti(gid)
if tile:
image = tmxdata.get_tile_image(x, y, layer)
By the way, excuse me for my language. Hopefully works.
Edit: You can look this video detailed for import tmx map in pygame. Video link: https://www.youtube.com/watch?v=QIXyj3WeyZM
Upvotes: 3