Как визуализировать изометрический тайловый мир в Python?

У меня возникли проблемы с визуализацией изометрического 2D-мира на основе плитки с использованием Python и Pygame со следующим кодом:

'''
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)

Используемый размер плитки 64x64; приведенный выше код при запуске генерирует следующий вывод: В этом примере показана плитка стены, но, очевидно, что-то идет не так, так как все плитки слишком далеко друг от друга.

Я пытался прочитать несколько руководств в Интернете, но я не могу найти ни одного, написанного на Python, поэтому, пожалуйста, сообщите мне, где я ошибаюсь.

Заранее спасибо, Ильмионт


person Ilmiont    schedule 17.12.2013    source источник


Ответы (2)


Попробуй это:

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

И, после теста, измените convert() на convert_alpha(), потому что оптимизация убивает альфу при convert()

Я также изменяю y ( /4*3 ), чтобы учесть ваше изображение. Это работа для меня.

person A.H    schedule 17.12.2013
comment
Это работает лучше, но теперь я получаю такой результат: i.stack.imgur.com/XJgBC.png Таким образом, черные треугольники (частично) остаются. - person Ilmiont; 17.12.2013
comment
Вы уверены, что эти черные части прозрачны? - person Matthias; 17.12.2013
comment
Можете ли вы разместить свою карту.png во вложении? Вы также можете попробовать: wall = pygame.image.load('wall.png').convert_alpha() - person A.H; 17.12.2013
comment
Итак, вот плитка «wall.png», которую я демонстрирую: i.stack.imgur.com /oBrF0.png - person Ilmiont; 17.12.2013
comment
Упс, извините... А.Г. был прав; Я не конвертировался в альфу. Итак, теперь карта отображается правильно, но она по-прежнему имеет неправильную форму... как мне отобразить ее в центре экрана??? - person Ilmiont; 17.12.2013
comment
На самом деле; Это не правильно. Плитки по-прежнему не выровнены правильно; посмотрите на это изображение: i.stack.imgur.com/Yfrjv.png - person Ilmiont; 17.12.2013
comment
Должно быть, что-то не так с моей картой, вот все, о чем я могу думать; любая помощь по-прежнему приветствуется. Спасибо пока; по крайней мере, теперь у меня работает прозрачность! - person Ilmiont; 17.12.2013
comment
Прочитайте ответ выше, я исправляю расчет y, который был неправильным в моей первой итерации. Если считать пиксели, высота составляет всего 48 пикселей (3/4). Итак, y=(cartx + carty)/4*3 - person A.H; 17.12.2013
comment
Снова лучше, но я хочу, чтобы все они были на одном уровне высоты... пожалуйста, посмотрите на картинку; должно быть что-то не так со структурой моей карты. Спасибо за помощь, и /4 * 3 снова улучшил его, но он далек от совершенства... i.stack.imgur.com/B2v75.png - person Ilmiont; 17.12.2013
comment
У вас есть проблема: с x = (cartx - carty) / 2 и y = (cartx + carty)/4 * 3 здесь все работает отлично. Я могу воспроизвести то, что у вас есть, если напишу: y = (cartx + carty /2 )/4*3, что НЕ то, что я написал - person A.H; 17.12.2013
comment
Я попытался отредактировать его снова, и он стал немного лучше; теперь это выглядит так, но все еще явно неправильно... кстати, я изменил плитки; красные - это стены, а синие - трава... не спрашивайте, почему они синие; Я просто быстро инвертировал цвета на красном! i.stack.imgur.com/nPIXL.png - person Ilmiont; 18.12.2013
comment
Наконец-то это работает! для строки в map_data: для плитки в строке: cartx = currentTile * tileWidth #x — это индекс currentTile * ширина плитки carty = currentRow * tileHeight #y — это индекс currentRow * высота плитки x = (cartx - carty) / 2 print(x) y = (cartx + carty) / 4 print(y) print('\n') if tile == 1: tileImage = wall else: tileImage = grass DISPLAYSURF.blit(tileImage , (x, y)) #отображаем текущий тайл currentTile += 1 currentTile = 0 currentRow += 1 - person Ilmiont; 19.12.2013
comment
Теперь мне нужно сделать так, чтобы он отображался посередине экрана, чтобы я мог видеть всю карту, но я думаю, что сделаю для этого новый пост, если мне понадобится помощь. Спасибо всем. - person Ilmiont; 19.12.2013

Вы можете избавиться от черных треугольников, установив цветной ключ на черный, я скопировал ваш пример и смог исправить его, изменив:

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

Найдено по адресу: https://www.pygame.org/docs/ref/surface.html#pygame.Surface.set_colorkey

Вероятно, есть лучший способ установить цветовую клавишу для всех, но я попробовал это, и, похоже, это работает. Я вижу комментарий об альфе, я уверен, что это тоже работает лучше.

Что касается позиционирования, вам просто нужно начать рендеринг с середины экрана. Я смог сделать это с помощью вашего кода, просто изменив:

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

to

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

Я надеюсь, что это поможет новичкам в этой теме!

person DevOops    schedule 17.07.2015