球体物理问题 Python

4

我正在尝试让一个球在一个盒子内正确地弹跳,特别是处理特定角度的角落和正面对着角落的情况。但我有一个问题,因为我的球总是跑出盒子外。我有一个函数来判断球是否跑出盒子,它可以处理角落和墙壁。代码如下:

    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编写的模板,或者一个您使用过的可以处理和执行我正在尝试处理和执行的相同任务的代码?请随意修改代码,只要让我知道即可。任何链接到已经解决此问题的内容都将非常好。谢谢。

不要写“这个不起作用”,尝试给出有帮助的描述,说明实际发生了什么。你是否在某个地方得到了异常?如果是这样,它是什么?你是否得到了意料之外的结果?如果是这样,它们是什么? - Ofri Raviv
好的观点。我明白了,我的错误是超出了参数范围。但是,它只是超出了网格一个单位,然后自己纠正了一下......这种情况可能只发生了大约一百次,在十万次移动中。 - TheChes44
1
关于如何让你的代码更易读,这里有一些提示。不要使用== True,如果你使用if tampered:同样可以达到同样的效果;此外,在if语句周围不需要加上( );最后,if not diff:if (diff == 0):更易读。 - gnur
好的,当它工作时,我会让它看起来很华丽。感谢您的建议。你知道出了什么问题吗? - TheChes44
如果您能够提供一个带有图形描述的“错误”轨迹的图表,那将会很有帮助。 - Open the way
@gpu_drug.....如果它是图形化的,我就能看到自己的错误了。所有这些都是在幕后发生的。没有GUI界面。如果我知道正在发生什么或球离开网格的位置,我会更具体。 - TheChes44
2个回答

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       

我喜欢你说的话,但是有一个问题,为什么它不起作用。我现在想不出来,因为我太累了,但是明天早上我会用清醒的眼睛回复你。不过这看起来是个不错的方法。 - TheChes44
我认为“velocity *= -1”不能很好地表示反射速度,因为只有速度的一个分量(在轴对齐的二维坐标系中的“X”或“Y”)应该被时间乘以-1。 - Steve H
抱歉,ofri,你需要帮助他知道反射速度应该是多少...这是一个“不那么琐碎”的问题,只是简单的边界框...即使不考虑下周TheChes44想要在管理反射速度的同时缓慢旋转正方形。 - Steve H
@Steve H - 速度不是向量!它是一维标量。它只是用于DRY处理2个轴。它实际上会执行您在第一条评论中编写的内容。 - Ofri Raviv
请原谅我,我得把我的脚从嘴里拿出来。我现在明白了。那很优雅。我部分地阅读了它,以为速度是一个向量。 - Steve H

1

pymunk已经做得如此出色时,您不应该重新发明这个轮子。 ;)


那是做什么用的?我该如何使用它? - TheChes44
看一下,这是一个二维刚体物理模拟。他们有一个演示应用程序与库一起使用,让您玩弄其中的功能。 - Joe
如果我不想要它用于图形目的......只是在底层,如果你能明白我的意思。这真的不是一款游戏,有没有办法我可以使用他们的Python代码? - TheChes44
没问题,如果您想将其连接到渲染引擎,则需要进行图形部分。Pymunk很高兴让您只需输入刚体位置并在随机时间间隔内获得它们的速度。我认为最好您查看链接并查看他们的演示以了解他们如何处理事情。设置非常容易,而且他们有一个友好、响应迅速的论坛。 - Joe
即使不是用于游戏开发,了解物体如何从盒子中漂移出去也很有用,因此Pymunk和Pygame在处理刚体碰撞方面非常实用。 - Joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接