I am using pytmx to load my map with pygame, but some items needs to be set as sprites and displayed above the surface, so the layering doesn't stay, I will show you 2 examples, one with the player displaying on top of decorations (where the point layer in under the decorations) the other one is the door displaying above the walls.
I tried to refresh my map with my player and door object by rewriting make_map() and render(surface) functions from Renderer, but instead of passing object I iterated threw them to blit the one it was, it has displaying, but still not layered, and also half FPS goes down.
Si if anyone knows how to be able to keep the layering even with player and other object used to render animated sprites I would be glad to get your help please.
This is the code I tried to use to refresh map every time with layering (it was displaying, but it has the exact same results as if I draw only the surface and then draw sprites above) :
def draw(self, display, camera = None):
self.surface = self.make_map()
self.rect = self.surface.get_rect()
if not camera:
display.blit(self.surface, self.rect)
else:
display.blit(self.surface, (self.rect.x - camera.offset.x, self.rect.y - camera.offset.y))
def render(self, surface):
tw = self.tmx_data.tilewidth
th = self.tmx_data.tileheight
if self.tmx_data.background_color:
surface.fill(self.tmx_data.background_color)
else:
surface.fill((0, 0, 0))
for layer in self.tmx_data.layers:
if isinstance(layer, pytmx.TiledTileLayer):
for x, y, image in layer.tiles():
if image:
surface.blit(image.convert_alpha() , (x * tw, y * th))
elif isinstance(layer, pytmx.TiledObjectGroup):
for tile_object in layer:
if tile_object.name == 'player':
surface.blit(self.level.game.player.image.convert_alpha(), (self.level.game.player.rect.x, self.level.game.player.rect.y))
if tile_object.name == 'door':
for door in self.level.game.doors:
if door.type == tile_object.type:
surface.blit(door.image.convert_alpha(), (door.rect.x, door.rect.y))
elif isinstance(layer, pytmx.TiledImageLayer):
if image:
surface.blit(image , (0, 0))
def make_map(self):
temp_surface = pygame.Surface(self.renderer.size)
self.render(temp_surface)
return temp_surface
So I have found a way to get what I wanted, I had used pyagme sprites groups layeredUpdates, I added to my original map only floor, I created layered sprites with my other layers (walls,decorations) and then displayed with the layer
The map rendering
def render(self, surface):
tw = self.tmx_data.tilewidth
th = self.tmx_data.tileheight
if self.tmx_data.background_color:
surface.fill(self.tmx_data.background_color)
else:
surface.fill((0, 0, 0))
for layer in self.tmx_data.layers:
if isinstance(layer, pytmx.TiledTileLayer):
for x, y, image in layer.tiles():
if image:
if layer.name == 'walls' or 'wall' in layer.name:
Wall(self.game, x * tw, y * th, image.convert_alpha())
elif 'decoration' in layer.name:
Decoration(self.game, x * tw, y * th, image.convert_alpha())
else:
surface.blit(image.convert_alpha() , (x * tw, y * th))
elif isinstance(layer, pytmx.TiledObjectGroup):
pass
elif isinstance(layer, pytmx.TiledImageLayer):
if image:
surface.blit(image , (0, 0))
def make_map(self):
temp_surface = pygame.Surface(self.size)
self.render(temp_surface)
return temp_surface
The objects :
class Decoration(pygame.sprite.Sprite):
def __init__(self, game, x, y, image, layer = DECORATION_TOP_LAYER):
self.groups = game.all_sprites, game.decorations
self._layer = layer
pygame.sprite.Sprite.__init__(self, self.groups)
class Wall(pygame.sprite.Sprite):
def __init__(self, game, x, y, image):
self.groups = game.all_sprites, game.walls
self._layer = WALL_LAYER
pygame.sprite.Sprite.__init__(self, self.groups)
class Door(pygame.sprite.Sprite):
def __init__(self, game, x, y, w, h, open_actions, animated_image, type):
self._layer = DOOR_LAYER
self.groups = game.all_sprites, game.doors
pygame.sprite.Sprite.__init__(self, self.groups)
class NPC(pygame.sprite.Sprite):
def __init__(self, game, x, y, w, h, animated_image):
self.groups = game.all_sprites, game.NPCs
self._layer = NPC_LAYER
pygame.sprite.Sprite.__init__(self, self.groups)
And the thing that makes all works together is simply :
self.all_sprites = pygame.sprite.LayeredUpdates()