3

所以我在写一个游戏。以下是碰撞检测的工作原理;有一个不可见的网格,对象(或者更确切地说,它们的引用)根据它们的位置从单元格中添加和删除。碰撞比较仅在同一单元格中的对象之间进行。

引用存储在set每个单元所拥有的 Python 中。它必须是一个集合。当检测到碰撞时,将其存储在Collision具有三个属性的对象中;碰撞的两个物体和发生碰撞的时间。当考虑到所有冲突时,它们会按时间排序,然后进行处理。

这是单个细胞用来检查碰撞的循环;

#grid.collisions is a list of recorded collisions, and self.objects is the set
#of objects currently in this cell.

for i in self.objects:
    for j in self.objects:
        if id(i) != id(j) and pygame.sprite.collide_rect(i, j):
            grid.collisions.append(Collision(i, j))

问题是,这会比较相同的两个对象两次;如果我们有一个 set {1, 2, 3, 4},我们会比较(1, 2) (2, 1)。不仅如此,这些重复的比较还被添加到冲突的总列表中,从而破坏了整个系统!

我知道我不能索引集合,这意味着我不能做像for j in range(i, len(self.objects))whereijare both integers 这样的事情。 如何绕过此限制以确保同一集合中的两个对象不会被比较两次? 我无法移除这些集合中的对象;只有当对象离开网格单元时,它们才会被移除。

由于每帧都会处理这些冲突,因此我宁愿避免创建新对象(实际代码不会Collisions像示例那样创建新对象,我只是为了便于阅读而对其进行了简化)。我可以删除重复的比较,但是将每个碰撞与其他碰撞进行比较将是很多开销。

4

3 回答 3

7

如果您的目标只是比较集合的所有独特组合,您可以使用itertools.combinations

from itertools import combinations

for i, j in combinations(self.objects, 2):
    if pygame.sprite.collide_rect(i, j):
        grid.collisions.append(Collision(i, j))

例子:

aSet = set([1,2,3,4])
list(combinations(aSet, 2))
# [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

combinations与管理多个索引和临时列表相比,生成一个非常高效的生成器

于 2012-07-24T05:03:30.550 回答
1

列个清单怎么样?

objects=list(self.objects)
for i in range(len(objects)):
  for j in range(i+1,len(objects)):
     if pygame.sprite.collide_rect(objects[i], objects[j]):
       grid.collisions.append(Collision(objects[i], objects[j]))

这是另一种选择:

objects=[]
for i in range(self.objects):
  for j in objects:
    if pygame.sprite.collide_rect(i, j):
      grid.collisions.append(Collision(i, j))
    objects.append(i)
于 2012-07-24T04:56:56.317 回答
1

在您的代码中更改!=为:<

for i in self.objects:
    for j in self.objects:
        if id(i) < id(j) and pygame.sprite.collide_rect(i, j):
            grid.collisions.append(Collision(i, j))
于 2012-07-24T05:14:33.813 回答