Python 球体物理问题

4 投票
2 回答
708 浏览
提问于 2025-04-16 19:18

我正在尝试让一个球在一个盒子里正确地反弹,特别是处理特定角度的角落和正面碰到角落的情况。不过我遇到了问题,因为我的球总是会跑出盒子。我有一个函数可以判断我的球是否出盒子,并且它能处理角落和墙壁。代码如下:

    if ((self._x > self._Grid.getWidth()) or (self._x < 0)):
        print("RandomNode:outside paramaters: x! self._x = %s , self._velx = %s" % (self._x , self._velx))
    if ((self._y > self._Grid.getLength())  or (self._y < 0)):
        print("RandomNode:outside paramaters: y!")
    if ((self._velx + self._x) > self._Grid.getWidth()):
        diff = self._Grid.getWidth()-self._x
        self._velx *= -1
        if (diff == 0):
            self._x -= self._velx
        else:
            self._x+= diff
        tampered = True
        #print("eqn1: self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))

    if (self._velx + self._x < 0):
        diff = self._x
        self._velx *= -1
        if (diff == 0):
            self._x += self._velx
        else:
            self._x-= diff
        tampered = True
        #print("eqn2: self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))


    if ((self._vely + self._y) > self._Grid.getLength()):
        diff = self._Grid.getLength()-self._y
        self._vely *= -1
        if (diff == 0):
            self._y -= self._vely
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn31:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx - diff)
                    self._y += self._vely
                    #print("eqn32:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn33:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))


        else:
            self._y+= diff
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn31:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx - diff)
                    self._y += self._vely
                    #print("eqn32:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn33:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))

    if (self._vely + self._y < 0):
        diff = self._y
        self._vely *= -1
        if (diff == 0):
            self._y += self._vely
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn41:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx + diff)
                    self._y += self._vely
                    #print("eqn42:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn43:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))

        else:
            self._y-= diff
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn41:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx + diff)
                    self._y += self._vely
                    #print("eqn42:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn43:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
    return tampered

我不知道为什么它不工作。x 和 y 显然是球的坐标。Velx 和 Vely 是它在 x 轴和 y 轴上的速度。Tampered 是一个布尔值,用来防止球正常移动,只能在检查的范围内移动。

我的问题是,这段代码有什么问题?或者……网上有没有用 Python 写的模板,或者你用过的代码,能做到我想要处理的事情?请随意修改代码,只要告诉我一声就行。任何已经解决的链接也非常欢迎。谢谢。

2 个回答

1

你不需要自己去重新发明这个轮子,因为pymunk已经帮你做得很好了。;)

7

重写这段代码吧。它对你想解决的简单问题来说,实在是太复杂了。

首先,一个球的二维运动其实可以看作是两个一维的问题。你可以把X轴和Y轴完全分开来处理。比如,球撞到一个角落,其实就等于先撞到X轴的墙,再撞到Y轴的墙。撞到X轴的墙只需要把X方向的速度反向(如果你想模拟能量损失,也可以考虑这一点)。撞到Y轴的墙则是反向Y方向的速度。

其次,因为处理X和Y的方式非常相似,可以把这部分代码提取成一个方法。

def handle_axis_movement(location, velocity):
    "returns updated location and velocity"
    ...

self.x, self.vel_x = handle_axis_movement(self.x, self.vel_x)
self.y, self.vel_y = handle_axis_movement(self.y, self.vel_y)

这样可以把代码量(和可能出现的错误)减少一半。

第三,你不需要把diff==0和diff<0这两种情况分开处理。这两种情况都意味着球撞到了墙,应该反向速度。然后你还需要调整位置,以确保球没有穿过墙。

location += velocity
if location > max_bound:
    location = max_bound - (location - max_bound)
    velocity *= -1
if location < min_bound:
    location = min_bound - (location - min_bound)
    velocity *= -1       

撰写回答