How to render an isometric tile-based world in Python?

8.5k views Asked by At

I'm having a bit of trouble rendering an isometric 2D tile-based world using Python and Pygame with the following code:

'''
Map Rendering Demo
rendermap.py
By James Walker (trading as Ilmiont Software).
Copyright (C)Ilmiont Software 2013. All rights reserved.

This is a simple program demonstrating rendering a 2D map in Python with Pygame from a list of map data.
Support for isometric or flat view is included.
'''

import pygame
from pygame.locals import *

pygame.init()

DISPLAYSURF = pygame.display.set_mode((640, 480), DOUBLEBUF)    #set the display mode, window title and FPS clock
pygame.display.set_caption('Map Rendering Demo')
FPSCLOCK = pygame.time.Clock()

map_data = [
[1, 1, 1, 1, 1],
[1, 0, 0, 0, 1],
[1, 0, 0, 0, 1],
[1, 0, 0, 0, 1],
[1, 0, 0, 0, 1],
[1, 1, 1, 1, 1]
]               #the data for the map expressed as [row[tile]].

wall = pygame.image.load('wall.png').convert()  #load images
grass = pygame.image.load('grass.png').convert()

tileWidth = 64  #holds the tile width and height
tileHeight = 64

currentRow = 0  #holds the current map row we are working on (y)
currentTile = 0 #holds the current tile we are working on (x)

for row in map_data:    #for every row of the map...
    for tile in row:
        tileImage = wall

        cartx = currentTile * 64    #x is the index of the currentTile * the tile width
        print(cartx)
        carty = currentRow * 64     #y is the index of the currentRow * the tile height
        print(carty)
        x = cartx - carty
        print(x)
        y = (cartx + carty) / 2
        print(y)
        print('\n\n')
        currentTile += 1    #increase the currentTile holder so we know that we are starting rendering a new tile in a moment

        DISPLAYSURF.blit(tileImage, (x, y)) #display the actual tile
    currentTile = 0 #reset the current working tile to 0 (we're starting a new row remember so we need to render the first tile of that row at index 0)
    currentRow += 1 #increment the current working row so we know we're starting a new row (used for calculating the y coord for the tile)

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYUP:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()

    pygame.display.flip()
    FPSCLOCK.tick(30)

The tile size used is 64x64; the above code when run generates the following output: enter image description here The tiles all have transparent edges and only the 'wall' tile is featured in this example but obviously something is going wrong as the tiles are all too far apart.

I have tried reading some tutorials online but I can't seem to find one actually written in Python so please advise me as to where I am going wrong.

Thanks in advance, Ilmiont

2

There are 2 answers

13
A.H On BEST ANSWER

Try this:

  print(carty)
  x = (cartx - carty) / 2
  print(x)
  y = (cartx + carty)/4*3

And, after test, modify convert() to convert_alpha(), because optimisation kill alpha on convert()

I also modify y ( /4*3 ), to take in account your image. It's work for me.

0
DevOops On

You can get rid of the black triangles by setting the colorkey to black, I copied your example and was able to fix it by changing:

for row in map_data:    #for every row of the map...
for tile in row:
    tileImage = wall

to

for row in map:
  for tile in row:
    tileImage = wall
    tileImage.set_colorkey((0,0,0))

Found from: https://www.pygame.org/docs/ref/surface.html#pygame.Surface.set_colorkey

There is probably a better way to set the colorkey for all, but I tried this and it seems to work. I see the comment about about alpha, I'm sure that works better too.

In regards to positioning, You would just need to start rendering from the middle of the screen. I was able to do this with your code by simple changing:

x = cartx - carty
print(x)
y = (cartx + carty) / 2

to

x = 320 + ((cartx - carty) / 2)
y = ((cartx+carty) / 4 * 3)

I hope this helps any newcomers to this thread!