【问题标题】:How to check if balls in a list collide, and remove them from list如何检查列表中的球是否碰撞,并将它们从列表中删除
【发布时间】:2013-05-03 23:56:27
【问题描述】:

所以我有一个看起来像这样的 Ball 类:

   class Ball(object):
    def __init__(self,n,x0,y0,dx,dy,r,c):
        self.xc = x0
        self.yc = y0
        self.dx = dx
        self.dy = dy
        self.radius = r
        self.area = math.pi*((r)**2)
        self.color = c
        self.name = n
    def position(self):
        return (self.xc,self.yc)
    def move(self):
        self.xc+=self.dx
        self.yc+=self.dy
    def collide(self,o,new_name):
        x = ((self.area*self.xc)+(o.area*o.xc))/(self.area+o.area)
        y = ((self.area*self.yc)+(o.area*o.yc))/(self.area+o.area)
        dx = ((self.area*self.dx)+(o.area*o.dx))/(self.area+o.area)
        dy = ((self.area*self.dy)+(o.area*o.dy))/(self.area+o.area)
        if self.area >= o.area:
            c = self.color
        else:
            c = o.color
        area = (self.area+o.area)
        r = math.sqrt(area/(math.pi))
        return Ball(new_name,x,y,dx,dy,r,c)
    def does_collide(self,o):
        if math.hypot((self.xc-o.xc),(self.yc-o.yc))<=(self.radius+o.radius):
            return True
        else:
            return False

我在我的主代码中运行了一个 while 循环来模拟各种球,每个球在每次迭代时都按其 dx 和 dy 值移动。为此,我有一个名为 balls 的列表,其中包含我所有的球对象。它看起来像这样:

    balls=[ball1,ball2,ball3,ball4...] and so forth

我想要做的是在我的球类中使用 dos_collide 函数来检查两个球是否发生碰撞,如果发生碰撞,我想从列表中删除两个球并在列表中插入一个新球,由碰撞功能。 collide 函数创建一个新球,其 x、y、dx 和 dy 值是两个球的加权平均值,其颜色是最大球的颜色。

那么对于我列表中的所有球,我如何使用 dos_collide 函数主动检查是否有任何两个球发生碰撞并将它们从列表中删除?我还想将新球添加到列表中,碰撞函数的结果。

我试着做这样的事情:

         for ball1 in balls:
            for ball2 in balls:
                if ball1.name!=ball2.name:
                    if ball1.does_collide(ball2) == True:
                        ball = ball1.collide(ball2,(int(N)+1))
                        balls.append(ball)
                        balls.remove(ball1)
                        balls.remove(ball2)

但这似乎很混乱,每次发生碰撞时都会崩溃。

【问题讨论】:

  • itertools.combinations 可以生成 2 元组进行比较并为您节省一些嵌套循环。
  • 您正在修改您正在迭代的列表,这绝不是一个好主意。
  • 请注意:尝试快速阅读Zen of Python,这是生成干净和 Pythonic 代码的精彩指南。我不知道你是否来自 Lisp-y 语言,但见鬼,你使用了很多不必要的括号!:)
  • 这些看起来更像是 C-heritage 的过度括号而不是 Lisp-heritage……但是是的,无论哪种方式,过度的括号总是使代码更难阅读。
  • 同时……你真的需要就地修改balls,而不是仅仅构建一个新的过滤balls来替换旧的吗?

标签: python list class simulation


【解决方案1】:

您关心订购吗?如果没有,这是您可以做到的一种方法。

import itertools

newballs = []
removed = set()
for b1, b2 in itertools.combinations(balls, 2):
    if b1 not in removed and b2 not in removed:
        if b1.does_collide(b2):
            removed.add(b1)
            removed.add(b2)
            newballs.append(b1.collide(b2))

balls = [b for b in balls if b not in removed] + newballs

【讨论】:

    【解决方案2】:

    让你的外循环遍历整个列表,但让你的内循环只从当前的外循环 ball+1 运行到列表的末尾。显然,如果 5 号球(例如)与 8 号球(例如)相撞,则 8 号球与 5 号球相撞,因此您不必同时检查两者。

    此外,您正在从列表中删除项目同时迭代列表。这不可能是安全的。我不会在循环内进行移除,而是在循环内设置标志,指​​示应该移除哪些球,然后在另一个循环中移除它们。

    【讨论】:

    • 就我个人而言,我发现只遍历数组的副本会更简单、更清晰。它还可以节省一些簿记。
    猜你喜欢
    • 1970-01-01
    • 2021-11-04
    • 2012-10-21
    • 1970-01-01
    • 2022-11-23
    • 2015-07-16
    • 1970-01-01
    • 2019-05-11
    • 2013-01-09
    相关资源
    最近更新 更多