如何在我的代码中修复“ IndexError:列表索引超出范围”?

时间:2019-10-14 17:10:43

标签: python list indexing

我对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 :(得分:0)

您之所以得到IndexError是因为您仅在tilemap中定义了一个行,但是外部for循环提供了{{1} }从row0的索引,原因如下:

mapheight-1

为避免该错误,请尝试将其更改为:

for row in range(mapheight):

更新

我想我已经弄清楚了您要做什么。正如我之前说的,for row in range(len(tilemap)): 是因为IndexError中的行数与您尝试使用嵌套tilemap循环显示的行数不匹配。

下面,我更正了for的定义方式,使其具有适当的行数和列数(还简化了一些其他定义,并在显示循环中添加了一些事件处理功能,以使脚本可以正常关机,而不是无限循环运行。

tilemap

答案 1 :(得分:0)

好吧,我终于明白了你在做什么。

即使您的图块是一维的,您也尝试制作第二个图块。对于多维数组,最好使用numpy数组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数组作为您的图块的模板,但是这次,我也正在投射一个数组,该数组将三色组映射到这些位置。 / p>

这样,您可以使用快速的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元素的长度设置为四个,以切换第四个元素的透明度。这样,您可以一次将位图创建为背景,然后直接在颜色四倍体上进行迭代,而无需在while循环的每次迭代中进行16 * 13慢速字典切片。显然,该绘图只是其外观的视觉展示,并且是用于对游戏地图进行建模的漂亮小工具。

并且由于它使用类型转换的numpy数组并避免了很多缓慢的操作,因此与以前相比,它应闪电般快。