pythonpygametmxpytmx

Rendering and refreshing tmx file map with python and pytmx


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.

Player on top of the decorations Layering in my map editor Door in my game Door in the map editor

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
    

Solution

  • 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()