2017-02-10 61 views
0

我有这段代码用Python编写,使用pygame在屏幕上显示对象,然后检测碰撞并删除对象发生碰撞。迭代遍历列表工作以相反的顺序进行但不通过列表前进(python/pygame)

当我有这样写的每次碰撞发生时的代码我得到这个错误:

代码:

for i in range(len(asteroids)): 
     asteroidObj = asteroids[i] 
     asteroidObj['rect'] = pg.Rect((asteroidObj['x'], 
             asteroidObj['y'], 
             asteroidObj['width'], 
             asteroidObj['height'])) 
     screen.blit(asteroidObj['surf'], asteroidObj['rect']) 
     asteroidObj['x']+= asteroidObj['xChange'] 
     asteroidObj['y']+= asteroidObj['yChange'] 
     if asteroidObj['rect'].colliderect(shipObj['rect']): 
      del asteroids[i] 

错误:

asteroidObj = asteroids[i] 
    IndexError: list index out of range 

但是,如果我改变for循环成为:

for i in range(len(asteroids)-1, -1, -1): 

该代码按预期工作,不再出现错误。

其中一个循环迭代从项目0-49和其他从49-0,所以我很困惑,为什么一个工作,一个没有。有谁知道这可能是为什么?

+0

因为当你删除项目25时,索引26处的索引现在位于索引25,索引49也不存在,所以你会在最后结束列表的末尾。 – mgilson

+0

因为如果按顺序遍历列表,当删除一个元素时,列表的长度会发生变化(变小),并且由于您的索引保持单调递增,您最终将索引超出范围。查看[this]的答案(http://stackoverflow.com/questions/6260089/strange-result-when-removing-item-from-a-list)问题,以便了解正在发生的事情。以相反的方式遍历列表可避免此问题。 –

回答

2

它只能反向工作,因为您要从列表中删除元素。例如,假设你有50个小行星,所以你的列表从0到49.小行星i==48碰撞,并且你从列表中删除它。现在你的列表长度为49(从0到48),但range(len(asteroids))已经被评估过了,在下一次迭代中你将有i==49,但是没有元素49了。它成为新的48时,你删除了前48个。

这样做倒过来,正如你的想法,是一种解决问题的方法,但我建议避免从列表中间删除元素,因为它是一个O (n)操作。我会做这样的事情:

new_asteroids = [] 
for asteroidObj in asteroids: 
    # Do your stuff here... 

    if not asteroidObj['rect'].colliderect(shipObj['rect']): 
     new_asteroids.append(asteroidObj) 
asteroids = new_asteroids