Python 如何检查列表中的球是否碰撞,并将其从列表中删除
我有一个球类课程,看起来像这样:Python 如何检查列表中的球是否碰撞,并将其从列表中删除,python,list,class,simulation,Python,List,Class,Simulation,我有一个球类课程,看起来像这样: 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
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
balls=[ball1,ball2,ball3,ball4...] and so forth
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)
我想做的是在我的ball类中使用does_collide函数来检查两个球是否发生碰撞,如果发生碰撞,我想从列表中删除这两个球,并在列表中插入一个由collide函数创建的新球。碰撞函数创建一个新球,其x、y、dx和dy值是两个球的加权平均值,其颜色是最大球的颜色
对于我列表中的所有球,我如何使用does_collide函数主动检查是否有任何两个球发生碰撞,并将它们从列表中删除?我还想将新球添加到列表中,这是碰撞功能的结果。
我试过这样做:
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
balls=[ball1,ball2,ball3,ball4...] and so forth
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)
但这似乎非常混乱,每次发生碰撞时都会崩溃。您关心订购吗?如果没有,这里有一种方法可以做到
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
你介意点菜吗?如果没有,这里有一种方法可以做到
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
让您的外循环运行在整个列表上,但让您的内循环仅从当前外循环球+1运行到列表的末尾。显然,如果球5(例如)与球8(例如)碰撞,那么球8与球5碰撞,因此您不必同时检查这两个
此外,在遍历列表的同时,您正在从列表中删除项目。这不安全。我不会在循环内执行删除操作,而是在循环内设置标志,指示应该删除哪些球,然后在另一个循环中删除它们。让您的外循环遍历整个列表,但让您的内循环仅从当前的外循环球+1运行到列表的末尾。显然,如果球5(例如)与球8(例如)碰撞,那么球8与球5碰撞,因此您不必同时检查这两个
此外,在遍历列表的同时,您正在从列表中删除项目。这不安全。我不会在循环内进行移除,而是在循环内设置标志,指示应该移除哪些球,然后在另一个循环中删除它们。
itertools.compositions
可以生成两个元组来比较并保存一些嵌套循环。您正在修改正在迭代的列表,这绝不是一个好主意。请注意:试着快速阅读,这是生成干净的Python代码的极好指南。我不知道您是否来自Lisp-y语言,但见鬼,您使用了很多不必要的括号!:)这些看起来更像是C-heritage多余的括号而不是Lisp heritage…但是,是的,不管怎样,过多的括号总是使代码更难阅读。同时…你真的需要在适当的位置修改balls
,与其只是构建一个新的过滤的balls
来替换旧的itertools。组合
可以生成两个元组来比较并保存一些嵌套循环。您正在修改您正在迭代的列表,这绝不是一个好主意。请注意:尝试快速阅读,这是一个很好的指南,可以生成干净的Python代码。我不知道您是否来自Lisp-y语言,但见鬼,您使用了很多不必要的括号!:)这些看起来更像是C-heritage多余的括号而不是Lisp heritage…但是,是的,不管怎样,过多的括号总是使代码更难阅读。同时…你真的需要在适当的位置修改balls
,与其仅仅构建一个新的过滤balls
来替换旧的,我个人觉得只需迭代数组的一个副本就更简单、更清晰了。这也节省了一些簿记工作。我个人认为,只需迭代数组的副本就可以了,而且更简单、更清晰。这也节省了一些簿记。