Search code examples
pythonpygametiles

How do i display tiles depending where they are?


How would I make some sort of an algorithm that displays the right image based on the tiles around it.

This is just how i define my level then i use a "for loop" to draw each tile to the screen

level = [
    ['1','1','1','1','1','1','1','1','1','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','0','0','1','1','1','0','0','0','1'],
    ['1','0','0','0','1','0','0','0','0','1'],
    ['1','0','0','0','1','1','0','0','0','1'],
    ['1','0','0','0','0','1','0','0','0','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','1','1','1','1','1','1','1','1','1'],
    ]

Now, i have a png file with all the tiles in it and i could display the corners and everything the right orientation if i wanted to, but if i were to just do a quick change to my map i would have to redo everything!

Would there be a way to display a different image on each tile based on what tiles are around it (so that in the corner in the top left it would detect the tile under it and to it's right, then display the right image depending on where it is)

Here is the entire code so you can test it!

import pygame

# Initialize Pygame
pygame.init()

# Set the size of the window
size = (360, 360)
screen = pygame.display.set_mode(size)

# Set the title of the window
pygame.display.set_caption("TILE MAP AAAaaAH")


tilesize = 30
level = [
    ['1','1','1','1','1','1','1','1','1','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','0','0','1','1','1','0','0','0','1'],
    ['1','0','0','0','1','0','0','0','0','1'],
    ['1','0','0','0','1','1','0','0','0','1'],
    ['1','0','0','0','0','1','0','0','0','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','0','0','0','0','0','0','0','0','1'],
    ['1','1','1','1','1','1','1','1','1','1'],
    ]
tiles = []
def build_level():
    x = 0
    y = 0
    for row in level:
        y += 1
        x = 0
        for tile in row:
            x += 1
            if tile == '1':
                build = pygame.Rect(x*tilesize, y*tilesize, tilesize, tilesize)
                tiles.append(build)
            if tile == '0':
                pass
build_level()

def draw_level():
    for tile in tiles:
        pygame.draw.rect(screen, (50, 50, 50), tile)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # Main Loop
    screen.fill((50, 50, 250))
    draw_level()


    pygame.display.update()

pygame.quit()

Solution

  • A fast way to do this would be to create a dictionary with tuple keys representing the presence or absence of a tile in the four cardinal directions, for example a key of (0, 0, 1, 1) could represent "no tile on the left", "no tile above", "a tile on the right", and "a tile below". Initialize the dictionary keys with the corresponding images. When drawing a tile, take its position, get the neighboring tiles (whether they are there or not), and arrange them in a tuple which would be used to get the corresponding image from the dictionary, here's a crude example similar to what you would do:

    # (left, top, right, bottom)
    images = {
        (1, 1, 1, 1): [all sides connected tile image],
        (0, 0, 0, 0): [normal tile image],
        (1, 0, 0, 0): [left connected tile image],
        (0, 1, 0, 0): [top connected tile image],
        (0, 0, 1, 0): [right connected tile image],
        (0, 0, 0, 1): [bottom connected tile image],
        (1, 1, 0, 0): [left and top connected tile image]
    }
    
    def get_tile_image(x: int, y: int) -> pygame.Surface:
        key = (level[y][x - 1], level[y - 1][x], level[y][x + 1], level[y + 1][x])
        return images[key]
    

    Make sure you consider that if the tile you are getting the image for is on the edge, there will be an index error, a few edge checks should fix it :)