我在pygame方面迈出了第一步,而且我已经使该程序正常工作。但是,在遍历main()数百次之后,它抛出“列表索引超出范围”消息。列表增加到一定限制后不会更改大小,因此我不确定错误发生在哪里。
运行程序后,只需在显示屏上移动鼠标,就会画出一圈圆圈,并随着时钟的滴答声而增大。最终,它将崩溃。
除了发生错误的行外,我已经省略了所有注释,希望这将使查找原因更加容易。
Stacktrace:
Traceback (most recent call last):
File "C:\Users\Devo\AppData\Local\Programs\Python\Python37-32\test files\Psychedelic Circles.py", line 89, in <module>
main()
File "C:\Users\Devo\AppData\Local\Programs\Python\Python37-32\test files\Psychedelic Circles.py", line 49, in main
drawCircles(snakeLength)
File "C:\Users\Devo\AppData\Local\Programs\Python\Python37-32\test files\Psychedelic Circles.py", line 75, in drawCircles
pygame.draw.circle(SCREEN, colorList[i], coords[i], abs(i-(len(coords))) * 5, 0)#### Why does the list index go out of range?
IndexError: list index out of range
import pygame, sys, random
from pygame.locals import*
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
FUSCHIA = (255, 0, 240)
GRAY = (80, 80, 80)
YELLOW = (255, 255, 0)
ORANGE = (255, 127, 0)
BLUE = (0, 0, 255)
INDIGO = (75, 0, 130)
VIOLET = (148, 0, 211)
FPS = 20
WWIDTH = 1000
WHEIGHT = 700
BIGBUTTON = pygame.Rect(0, 0, 1000, 700)
rainbowTuple = (RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET)
def main():
global SCREEN, FPS, colorList, coords, snakeLength
pygame.init()
clock = pygame.time.Clock()
size = (WWIDTH, WHEIGHT)
SCREEN = pygame.display.set_mode(size)
pygame.display.set_caption('Psychedelic Circles')
colorList = []
coords = []
snakeLength = 50 ### Change this value to make the circles disappear more quickly or slowly
while True:
clickedButton = None
SCREEN.fill(GRAY)
drawButtons()
checkForQuit()
for event in pygame.event.get():
if event.type == MOUSEMOTION:
mousex, mousey = event.pos
clickedButton = getButtonClicked(mousex, mousey)
if clickedButton == FUSCHIA:
sendCoords(mousex, mousey)
drawCircles(snakeLength)
pygame.display.update()
clock.tick(FPS)
def terminate():
pygame.quit()
sys.exit()
def sendCoords(x, y):
coords.append((x, y))
colorList.append(random.choice(rainbowTuple))
def checkForQuit():
for event in pygame.event.get(QUIT):
terminate()
for event in pygame.event.get(KEYUP):
if event.key == K_ESCAPE:
terminate()
pygame.event.post(event)
def drawButtons():
pygame.draw.rect(SCREEN, FUSCHIA, BIGBUTTON)
def drawCircles(snakeLength):
for i in range(len(coords)):
pygame.draw.circle(SCREEN, colorList[i], coords[i], abs(i-(len(coords))) * 5, 0)#### Why does the list index go out of range?
if i > snakeLength :
popList()
def popList():
coords.pop(0)
colorList.pop(0)
def getButtonClicked(x, y):
if BIGBUTTON.collidepoint((x, y)):
return FUSCHIA
return None
if __name__ == '__main__':
main()
答案 0 :(得分:4)
我怀疑仅当事件队列中存在多个鼠标移动事件时才会发生此错误。通常,pygame的速度足以在不产生一个新用户输入事件的情况下渲染屏幕,因此sendCoords
仅在drawCircles
个调用之间被调用一次。在这种情况下,coords
的大小永远不会超过52。但是,如果发生多个鼠标移动事件(可能是由于系统滞后,或者因为用户非常快地摇动了鼠标),则sendCoords
可能是连续叫了很多遍。因此,到drawCircles
执行时,coords
可以包含53个元素,甚至更多。
当您到达drawCircles
时,这将成为问题:
def drawCircles(snakeLength):
for i in range(len(coords)):
pygame.draw.circle(SCREEN, colorList[i], coords[i], abs(i-(len(coords))) * 5, 0)#### Why does the list index go out of range?
if i > snakeLength :
popList()
比方说,该函数在coords
包含53个元素且snakeLength
为50时执行。循环将正常迭代,直到i
等于51。然后i > snakeLength
将求值设为True,将调用popList
。现在coords
小一个元素,长度为52。循环的迭代结束,下一次迭代开始。 i
等于52。pygame.draw.circle
行将尝试访问coords[i]
,但是由于coords
不再具有53个元素,coords[i]
将引发IndexError尝试访问第53个元素。
Python不够聪明,无法理解如果for i in range(len(coords))
的大小减小1,则coords
循环应比平常提前一个迭代结束。不管列表是否会导致崩溃,它都会愉快地一直迭代到列表的原始长度。
一种可能的解决方案是将popList
移出列表,因此coords
的大小在迭代时不会改变。
def drawCircles(snakeLength):
for i in range(len(coords)):
pygame.draw.circle(SCREEN, colorList[i], coords[i], abs(i-(len(coords))) * 5, 0)#### Why does the list index go out of range?
while len(coords) > snakeLength :
popList()
您可能会想:“当在for循环中不能修改coords
的长度时,为什么可以在此while循环中修改它的长度呢?”关键区别在于这两个语句的评估时间。 range(len(coords))
仅在循环开始前执行一次,因此不会注意到对coords
的修改。但是len(coords) > snakeLength
在while循环的迭代开始时执行,因此对coords
的更改会立即被注意到。