[英]How to fix “IndexError: List index is out of range” in my code?
I am quite new to Python, and I wanted to test out a tilemap system.我对 Python 很陌生,我想测试一个瓷砖地图系统。 When I try to load the tiles, i get the error message
IndexError: list index out of range
.当我尝试加载图块时,我收到错误消息
IndexError: list index out of range
。 What do I need to do in order to solve this issue, and others like it in the future?为了解决这个问题,我需要做些什么,以及其他人将来喜欢它? Exact error:
确切的错误:
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
I have heard that it means I am trying to access a value which is none
or empty.我听说这意味着我正在尝试访问一个
none
或空的值。 Here is the part of the code that is about the tilemap
.这是关于
tilemap
的代码部分。 Without the last drawing bit, the rest works fine.没有最后一个绘图位,rest 工作正常。 (It's not a lot of other code, just movement.)
(这不是很多其他代码,只是运动。)
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()
You're getting the IndexError
because you've only defined one row in your tilemap
, but the outer for
loop supplies row
indices from 0
to mapheight-1
because of this statement:您收到
IndexError
是因为您只在tilemap
中定义了一行,但是由于以下语句,外部for
循环提供了从0
到mapheight-1
的row
索引:
for row in range(mapheight):
To avoid that error, try changing it to:为避免该错误,请尝试将其更改为:
for row in range(len(tilemap)):
Update更新
I think I've figured out what you're trying to do.我想我已经弄清楚你想要做什么了。 As I said previously, the
IndexError
is because the number of rows in tilemap
didn't match the number you were trying to display with the nested for
loops.正如我之前所说,
IndexError
是因为tilemap
中的行数与您尝试使用嵌套for
循环显示的行数不匹配。
Below I've fixed the way tilemap
is defined so it has the proper number of row and columns (and also streamlined a few other definitions and added some event processing to the display loop to allow the script to be gracefully shutdown instead of running in an infinite loop).下面我已经修复了
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()
Ok I finally understood what you are doing.好的,我终于明白你在做什么了。
You tried to do a second slice of your tilemap, even though your tilemap is one dimensional.即使您的 tilemap 是一维的,您也尝试对您的 tilemap 进行第二个切片。 For multidimensional arrays, it's best to use numpy arrays imo.
对于多维 arrays,最好使用 numpy arrays imo。 You'll see what I mean when you print out the tmap in my code, it's much more readable.
当您在我的代码中打印出 tmap 时,您会明白我的意思,它更具可读性。 Also, since python works with indents, it's a good idea to organize long function calls by separating different arguments to separate lines.
此外,由于 python 与缩进一起使用,因此通过将不同的 arguments 分隔为单独的行来组织长 function 调用是一个好主意。 Othewise you get a really unreadable long line in your code.
否则,您的代码中会出现非常难以阅读的长行。
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()
EDIT: I noticed that you do a lot of dictionary slices, which are very slow.编辑:我注意到你做了很多字典切片,非常慢。 If you do not need to repeatedly slice a dictionary inside the game loop (ie the map doesn't change), don't.
如果您不需要在游戏循环中重复切片字典(即 map 不会更改),请不要。 I've written a bit of extra code, which produces the same
tmap
array as above as a template for your tiles, but this time, I'm also casting an array, which maps color triplets to these positions.我已经编写了一些额外的代码,它会生成与上面相同的
tmap
数组作为图块的模板,但是这一次,我还要转换一个数组,它将颜色三元组映射到这些位置。
This way you can create your whole map once using fast numpy arrays, which utilize dtype typecasting of your array, while still benefitting from the readibility of the previously specified tmap.通过这种方式,您可以使用快速 numpy arrays 一次创建整个 map,它利用阵列的 dtype 类型转换,同时仍受益于先前指定的可读性。
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)
As you can see, matplotlib
can easily visualise X,Y,Z arrays, which the imshow()
function can read as a bitmap. As you can see,
matplotlib
can easily visualise X,Y,Z arrays, which the imshow()
function can read as a bitmap. X are the rows, Y are the columns and Z are the color triplets. X 是行,Y 是列,Z 是颜色三元组。 I actually made Z four elements long to toggle transparency with the fourth element.
实际上,我将 Z 设为四个元素,以便用第四个元素切换透明度。 This way you can create your bitmap once as a background and then just iterate directly over the color quadruples, without doing 16*13 slow dictionary slices at every iteration of the while loop.
这样,您可以创建一次 bitmap 作为背景,然后直接在颜色四元组上进行迭代,而无需在 while 循环的每次迭代中执行 16*13 慢速字典切片。 The plotting, obviously, is just a visual demonstration of what it will look like and is a nifty little tool for modelling your game map.
显然,绘图只是它外观的视觉演示,并且是一个漂亮的小工具,用于为您的游戏 map 建模。
And because it uses typecasted numpy arrays and avoids a lot of slow operations, it should be lightning fast compared to before.而且因为它使用了类型转换的 numpy arrays 并且避免了很多缓慢的操作,因此与以前相比应该快如闪电。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.