使用Python和Box2D进行简单的空间模拟

哈Ha

本文的灵感来自于最近出版的《建模宇宙》,其中作者展示了各种宇宙现象的非常有趣的模拟。但是,对于初学者来说,此处提供的代码并不容易。我将通过仅编写几行代码,向您展示如何使用Box2D引擎进行物理模拟

我会冒险犯一个错误,但这是Habré上对Python的Box2D的首次描述,我们填补了这一空白。



对于那些对它的工作方式感兴趣的人,细节在下面。

Box2D是由Blizzard Erin Catto创建的免费跨平台库。该库于2007年引入,如今已移植到几乎所有平台。Python也有一个端口,它的描述相当混乱,但是我希望在本文的帮助下,一切都会变得更加清晰。

介绍


pybox2d由两个组件组成-Box2D本身,用于物理建模的跨平台库以及称为框架的单独渲染模块。如果要在屏幕上查看创建的对象,则需要渲染,这对于我们的仿真足够方便。 Framework类可以使用各种输出方法(更多信息请参见),我们将使用pygame。如果安装了pygame库,则会自动“选择”它,而无需执行其他任何操作。要安装,只需输入pip install Box2D pygame命令

使用Box2D的最小运行程序如下所示。该代码是跨平台的,并且可以在Linux和Windows上的任何地方使用。

from Box2D.examples.framework import Framework
from Box2D import *

class Simulation(Framework):
    def __init__(self):
        super(Simulation, self).__init__()

        # Ground body
        self.world.CreateBody(shapes=b2LoopShape(vertices=[(20, 0), (20, 40), (-20, 40), (-20, 0)]))
        # Dynamic body
        circle = b2FixtureDef(shape=b2CircleShape(radius=2), density=1, friction=1.0, restitution=0.5)
        self.world.CreateBody(type=b2_dynamicBody, position=b2Vec2(0,30), fixtures=circle, linearVelocity=(5, 0))

    def Step(self, settings):
        super(Simulation, self).Step(settings)

if __name__ == "__main__":
    Simulation().run()

如您所见,我们正在创建一个Simulation类,该类继承自已经提到的Framework。接下来,我们通过调用CreateBody方法创建两个对象。第一个是静态对象,它定义了我们世界的边界。第二个对象是b2_dynamicBody类型,其他参数(形状,大小,密度,摩擦系数,初始速度)从代码中显而易见。在仿真过程中,每次都会调用Step函数,以后我们将使用它。例如,如果不需要UI,我们为服务器做一个后端,那么当然可以省略Framework类,但是对我们来说很方便。

就这样,运行程序并查看完成的模拟:



如您所见,我们仅创建了两个对象并指定了它们的参数。一切都“开箱即用”-重力,摩擦,弹性,物体的相互作用等。基于此,我们可以进行“空间”模拟。

我们发射“卫星”


不幸的是,Box2D中没有对牛顿重力的内置支持,您必须自己添加“步进”功能来添加它。对于第一个测试,我们将创建两个物体-一个行星和一个围绕它旋转的卫星。

整体源代码:

from Box2D import *
from Box2D.examples.framework import Framework


class Simulation(Framework):
    def __init__(self):
        super(Simulation, self).__init__()

        # Default gravity disable
        self.world.gravity = (0.0, 0.0)
        # Gravity constant
        self.G = 100

        # Planet
        circle = b2FixtureDef(shape=b2CircleShape(radius=5), density=1, friction=0.5, restitution=0.5)
        self.world.CreateBody(type=b2_dynamicBody, position=b2Vec2(0,0), fixtures=circle)

        # Satellite
        circle_small = b2FixtureDef(shape=b2CircleShape(radius=0.2), density=1, friction=0.5, restitution=0.2)
        self.world.CreateBody(type=b2_dynamicBody, position=b2Vec2(0, 10), fixtures=circle_small, linearVelocity=(20, 0))

    def Step(self, settings):
        super(Simulation, self).Step(settings)

        # Simulate the Newton's gravity
        for bi in self.world.bodies:
            for bk in self.world.bodies:
                if bi == bk:
                    continue

                pi, pk = bi.worldCenter, bk.worldCenter
                mi, mk = bi.mass, bk.mass
                delta = pk - pi
                r = delta.length
                if abs(r) < 1.0:
                    r = 1.0

                force = self.G * mi * mk / (r * r)
                delta.Normalize()
                bi.ApplyForce(force * delta, pi, True)

if __name__ == "__main__":
    Simulation().run()

如您所见,我们通过将self.world.gravity参数设置为0来“关闭”标准重力。我们还添加了参数G,这是虚拟世界的“重力常数”,用于计算Step方法。我们还创建了两个对象-卫星和行星。重要的是要注意密度和半径参数。根据这些参数,Box2D库本身将计算在计算中使用的质量。为了计算相互作用力,使用牛顿万有引力定律的 “学派”公式



现在开始仿真。我们没有达到第一宇宙速度,尽管卫星仍然绕着整个行星旋转,但很难称其为“飞行”:我们



通过将代码行更改为linearVelocity =(28,0)来提高速度:



我们的“卫星”已成功进入“行星”周围的轨道!如果进一步提高速度,则轨道将变为椭圆形:



最后,我们将描绘更类似于“太阳系”的东西,在不同的轨道上添加三个不同大小的行星:

circle_small = b2FixtureDef(shape=b2CircleShape(radius=0.2), density=1, friction=0.5, restitution=0.2)
circle_medium = b2FixtureDef(shape=b2CircleShape(radius=0.3), density=1, friction=1.0, restitution=0.5)
self.world.CreateBody(type=b2_dynamicBody, position=b2Vec2(0, 6), fixtures=circle_small, linearVelocity=(37, 0))
self.world.CreateBody(type=b2_dynamicBody, position=b2Vec2(0, 10), fixtures=circle_small, linearVelocity=(28, 0))
self.world.CreateBody(type=b2_dynamicBody, position=b2Vec2(0, 15), fixtures=circle_medium, linearVelocity=(22, 0))

结果:



我们看到行星离“太阳”越远,其旋转周期就越长(开普勒第三定律)。不幸的是,Box2D引擎不允许在屏幕上绘制运动轨迹,因此很难“看到”开普勒的第一定律和第二定律,但是您可以肯定它们也已实现。

结论


如您所见,使用Box2D,可以轻松完成简单的仿真。当然,该引擎仍然是游戏引擎,而不是科学引擎,因此您不应期望它会正确模拟银河系碰撞或物质爆炸期间的物质膨胀。但是有些模式值得关注。

所有的构思都不合适。如果估计为正,则在第二部分中将有可能考虑更多非平凡的例子。

All Articles