Как исправить «IndexError: Список индекса вне диапазона» в моем коде? - PullRequest
1 голос
/ 14 октября 2019

Я новичок в Python, и я хотел протестировать систему tilemap. Когда я пытаюсь загрузить плитки, я получаю сообщение об ошибке IndexError: list index out of range. Что мне нужно сделать, чтобы решить эту проблему, и другим она понравится в будущем? Точная ошибка:

Traceback (most recent call last):
  File "N:/Python/Projects/Projects/First Topdown/First Topdown.py", line 114, in <module>
    pygame.draw.rect(screen, colors[tilemap[row][column]], (column*tilesize, row*tilesize, tilesize, tilesize))
IndexError: list index out of range

Я слышал, что это означает, что я пытаюсь получить доступ к значению none или пусто. Вот часть кода, которая о tilemap. Без последнего бита рисования, остальное работает нормально. (Это не так много другого кода, только движение.)

import pygame

pygame.init()

tilesize = 64
mapwidth = 16
mapheight = 13
screen = pygame.display.set_mode((mapwidth*tilesize, mapheight*tilesize))


pygame.display.set_caption("Aspen")

WALLTOP = 0
WALLBOT = 1
GRASS = 2
wallTop = (128, 128, 128)
wallBot = (210, 105, 30,)
grass =   (50, 205, 50)

colors = {
WALLTOP : wallTop,
WALLBOT: wallBot,
GRASS : grass
}

tilemap = [
            [WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP,
            WALLTOP, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, WALLTOP,
            WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP]
]


running = True
while running:

    screen.fill((64, 64, 64))

    for row in range(mapheight):
        for column in range(mapwidth):
            pygame.draw.rect(screen, colors[tilemap[row][column]], (column*tilesize, row*tilesize, tilesize, tilesize))

    pygame.display.update()

Ответы [ 2 ]

0 голосов
/ 14 октября 2019

Хорошо, я наконец-то понял, что вы делаете.

Вы попытались сделать второй фрагмент вашей карты тайлов, даже если ваша карта тайлов является одномерной. Для многомерных массивов лучше всего использовать numy массивы imo. Вы поймете, что я имею в виду, когда распечатаете tmap в моем коде, он станет более читабельнымКроме того, поскольку python работает с отступами, рекомендуется организовывать длинные вызовы функций, разделяя разные аргументы на отдельные строки. В противном случае вы получите действительно нечитаемую длинную строку в вашем коде.

import pygame
import numpy as np

pygame.init()

# Define base values for tiles
tsize, width, height = 64,16,13

# Set the stage with an empty 2D array full of zeroes
# Create the tilemap dynamically from width and height.
tmap = np.zeros((height,width),dtype=int)

# defines the screen I guess?
screen = pygame.display.set_mode((width*tsize, height*tsize))
pygame.display.set_caption("Asspain")

# You can now change the tilemap manually.
# You have three unique rows, so you can
# just make lists of those and later insert
# them into your np.array
r1 = [1]*width

r2 = [1]
r2.extend([2]*14)
r2.extend([1])

r3 = [1]
r3.extend([0]*14)
r3.extend([1])

# turn your lists into np.arrays so they work
# with your tmap.
r1, r2, r3 = np.array(r1),np.array(r2),np.array(r3)

# insert the rows at the appropreate positions
# mind you, indexing works a bit different in
# np.arrays than in python builtin lists.
tmap[0] = r1.copy()
tmap[1] = r2.copy()
tmap[2:12] = r3.copy()
tmap[12] = r1.copy()

# You now have a nice and readable tmap.
# You can make the map creation process
# as manual as you want, I just used shortcuts
# based on symmetry.
print(tmap)

# Now you can just iterate over every element
# via double iteration, or using indices.
# I've heard iterating over indices using range
# is always faster.

# define colormap
cmap = {0:(50, 205, 50),
        1:(128, 128, 128),
        2:(210, 105, 30,)}

# this is unneccessary, but it's good to know
# that numpy arrays also have a len() like
# attribute called shape.
width, heigth = tmap.shape[0], tmap.shape[1]

# Gameloop
while True:

    # Is this the default color of a tile?
    # Do you need that?
    screen.fill((64, 64, 64))

    for row in range(width):
        for col in range(heigth):
            pygame.draw.rect(screen, 
                             cmap[tmap[row][col]],
                             (col*tsize,
                              row*tsize,
                              tsize,
                              tsize))
    pygame.display.update()

РЕДАКТИРОВАТЬ: я заметил, что вы делаете много кусочков словаря, которые очень медленные. Если вам не нужно многократно разрезать словарь внутри игрового цикла (то есть карта не меняется), не делайте этого. Я написал немного дополнительного кода, который производит тот же массив tmap, что и выше, в качестве шаблона для ваших плиток, но на этот раз я также приводю массив, который отображает триплеты цвета на эти позиции.

Таким образом, вы можете создать всю свою карту за один раз, используя быстрые массивы numpy, которые используют типотипирование dtype вашего массива, но при этом все еще выигрывают от читабельности ранее указанного tmap.

import numpy as np
import matplotlib.pyplot as plt

tsize, width, height = 64,16,13
tmap = np.zeros((height,width),dtype=int)
cmap = np.zeros((height,width,4),dtype=int)

r1 = [1]*width

r2 = [1]
r2.extend([2]*14)
r2.extend([1])

r3 = [1]
r3.extend([0]*14)
r3.extend([1])

r1, r2, r3 = np.array(r1),np.array(r2),np.array(r3)

tmap[0] = r1.copy()
tmap[1] = r2.copy()
tmap[2:12] = r3.copy()
tmap[12] = r1.copy()

cdct = {0:np.array((50, 205, 50, 200),dtype=int),
        1:np.array((128, 128, 128, 200),dtype=int),
        2:np.array((210, 105, 30, 200),dtype=int)}

for posy, row in enumerate(tmap):
    for posx, col in enumerate(row):
        cmap[posy,posx] = cdct[col].copy()

fig, ax = plt.subplots()
plt.axis('off')

ax.imshow(cmap)

Как вы можете видеть, matplotlib может легко визуализировать массивы X, Y, Z, которые функция imshow() может читать как растровое изображение. X - строки, Y - столбцы, а Z - триплеты цвета. Я фактически сделал Z из четырех элементов длинным, чтобы переключать прозрачность с четвертого элемента. Таким образом, вы можете создать свое растровое изображение один раз в качестве фона, а затем просто выполнить итерацию непосредственно по цветным четверкам, не делая 16 * 13 медленных кусочков словаря на каждой итерации цикла while. Очевидно, что построение графиков является лишь наглядной демонстрацией того, как оно будет выглядеть, и является изящным небольшим инструментом для моделирования игровой карты.

И поскольку он использует типизированные массивы и избегает множества медленных операций, ондолжен быть молниеносным по сравнению с предыдущим.

0 голосов
/ 14 октября 2019

Вы получаете IndexError, потому что вы определили только одну строку в вашем tilemap, но внешний цикл for поставляет row индексы от 0 до mapheight-1 из-за этого утверждения:

for row in range(mapheight):

Чтобы избежать этой ошибки, попробуйте изменить ее на:

for row in range(len(tilemap)):

Обновление

Я думаю, что яВыяснили, что вы пытаетесь сделать. Как я уже говорил ранее, IndexError заключается в том, что число строк в tilemap не совпадает с числом, которое вы пытаетесь отобразить с помощью вложенных циклов for.

Ниже я исправилспособ tilemap определен так, чтобы он имел правильное количество строк и столбцов (а также упорядочил несколько других определений и добавил некоторую обработку событий в цикл отображения, чтобы позволить сценарию изящно завершить работу вместо выполнения в бесконечном цикле.

import pygame

pygame.init()

tilesize = 64
mapwidth, mapheight = 16, 13

screen = pygame.display.set_mode((mapwidth*tilesize, mapheight*tilesize))

pygame.display.set_caption("Aspen")

WALLTOP, WALLBOT, GRASS = range(3)

wallTop = (128, 128, 128)
wallBot = (210, 105, 30,)
grass =   (50, 205, 50)

colors = {
    WALLTOP : wallTop,
    WALLBOT : wallBot,
    GRASS   : grass
}

tilemap = [
    [WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP],
    [WALLTOP, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLBOT, WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   GRASS,   WALLTOP],
    [WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP, WALLTOP],
]

running = True
while running:

    screen.fill((64, 64, 64))

    for row in range(mapheight):
        for column in range(mapwidth):
            pygame.draw.rect(screen, colors[tilemap[row][column]], (column*tilesize, row*tilesize, tilesize, tilesize))

    # Process user-events.
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # User clicked to close window.
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE: # Press escape key to quit.
                running = False

    pygame.display.update()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...