进阶

在这一节中,我们将讨论不同的“高级”主题,当您使用Pymunk时,通常不需要担心这些内容,但如果您想更好地了解Pymunk,例如扩展它,您可能会感兴趣。

首先,Pymunk是一个围绕C库Chipmunk2D构建的 Python 函数库,它提供了几乎所有围绕物理模拟的基本功能,如碰撞检测、脉冲解算等。基本上,它运行模拟,并通过输入调用它,并接收结果。

为了包装Chipmunk,Chipmunk在API模式下使用CFFI。在CFFI包装的顶部是一个手工的Python层,这使得它可以很好地从Python代码使用。

脉冲求解器算法

Chipmunk本身只执行最少量的物理计算,而不是由底层的C库Chipmunk2D处理这些计算。Chipmunk2D(以及因此的Pymunk)使用标准Euler来执行积分

Scott/slembcke(Chipmunk2D的创建者)写了这篇文章来描述在 Chipmunk2D Forum

Chipmunk的工作原理如下:

  1. 积分所有物体的位置,找出碰撞对。

  2. 预计算触点和运动类型的许多特性。(质量属性、反弹速度等)

  3. 整合一切事物的速度。

  4. 运行多次解算器迭代,以修复速度约束。

案例1,地上有一个盒子:

  1. 盒子是静止的,它的速度是(非常接近)零,它的位置不变。产生与地面的接触。

  2. 预计算接触特性,如果设置了弹性,则现在将计算“反弹”速度(为0)。

  3. 积分速度,重力使物体向下加速。

  4. 解决接触问题。速度应收敛回0。如果设置了弹性,则无需求助于阈值速度即可正确处理。

#1真的是最重要的部分。如果在定位之前更新速度,则会导致长方体自身移动到与地面相交的位置。虽然Chipmunk无论如何都要解决这些重叠问题,但避免它们似乎是可取的。另一个非常有用的属性是,当cpSpaceStep()返回时,所有冲突检测数据结构都是最新的。如果您想要进行查询,则不需要在单个框架中对它们进行两次重新索引。

碰撞检测算法

与脉冲解算器一样,碰撞检测也由底层C库Chipmunk2D处理。

Chipmunk使用GJK/EPA来查找复杂情况(如多边形、线段形状)之间的冲突。有一篇博客文章 here 更多细节。

为什么是CFFI?

这是跟踪CFFI升级的GitHub问题的直接副本。Https://github.com/viblo/pymunk/issues/99

CFFI有很多优点,但也有缺点。

优势(与ctype相比):

  • 这是一个活跃的项目。开发者和用户都很活跃,有新的版本正在发布,可以在一天内在CFFI邮件列表上询问和获得答案。

  • 据说这是PyPy的前进方向,承诺会比ctype有更好的性能。

  • 比ctype更容易包装东西,因为您只需复制粘贴c头文件。

缺点(与ctype相比):

  • Ctype是CPython标准库的一部分,而CFFI不是。这意味着,如果使用CFFI,安装Pymunk将变得更加困难,因为复制粘贴安装不再是一种简单的方式。

对我来说,我认为第一个优势是主要的。我在Windows上遇到了64位 Python 的奇怪的段错误,有时在32位的Python上也遇到了很大的困难,我真的想在Windows和Linux上支持64位的Python。希望CFFI能够更容易地处理这些问题,因为它有一个活跃的社区。

然后是第三个优点,它更容易包装c代码。对于ctype,我有一个自动包装脚本,它执行大多数低级包装,但它不受支持,很难设置(我只在使用Linux的VM中管理),而且相当烦人。CFFI将是一个明显的进步。

对于ctype的缺点,我认为它是可以接受的,即使不是理想的。许多python包都必须以某种方式安装(比如pyGame),现在使用pip安装起来非常容易。所以我希望一切都会好起来的。

有关最初使用ctype的原因,请参阅下一节。

为什么是ctype?(已过时)

使用ctype而非ctype的原因 [your favorite wrapping solution] 可以概括为

  • 只需在包装时编写纯Python代码即可。这是好的,有几个原因。我真的不能用c编写代码。当然,我可以读懂它,写一些简单的东西,但我不是一个很好的c程序员。我非常了解的是 Python 。我想对于大多数使用派慕克的人来说也是一样的,毕竟它是一个 Python 程序库。:)希望这意味着Chipmunk的用户可以非常容易地看到事情是如何实际完成的,例如,在他们自己的代码中自己添加一个丢失的Chipmunk方法/属性,而不会有太多问题,并且不需要编译/构建任何东西。

  • Ctype包含在标准库中。任何拥有它的人都已经有了它,不依赖于第三方库,一些人保证它会长期存在。

  • 运行Chipmunk所需要的唯一东西是python和一个c编译器(在这些情况下,不包括预构建版的Chipmunk)。这应该会最大限度地提高pymunk的跨平台性,唯一会更好的是一个纯的python库(出于其他原因,这可能不是一个好主意,主要是速度)。

  • 没有太多的魔法在上演。使用ctype非常简单。当然,Chipmunk使用的生成器有点麻烦,但如果需要的话,至少可以避开它,我在某些情况下就这样做了。我也遇到过一些问题,当事情没有像预期的那样工作时,但我想如果用其他解决方案,情况会更糟。至少它是唯一的c库和python,而不是介于两者之间的某个第三方。

  • Chipmunk的非API破解修复不会影响Chipmunk。如果在Chipmunk中进行了错误修复、一些优化或任何不会影响API的操作,那么使用新代码重新编译Chipmunk就足够了,这样就可以从修复中受益。对每个人来说都很容易。

  • Ctype可以在除cpython之外的其他python实现上运行。目前,PyPy感觉最有前途,而且它能够很好地运行ctype。

在我看来,另一种解决方案可能带来的主要好处是速度。然而,我有几个理由认为这不像ctype的好处那么重要

  • 你一开始就是用python编写游戏的,如果你真的想要最高的性能,也许用c重写整个游戏会更好?或者对Chipmunk进行优化绑定。

    例如,如果您真的需要出色的性能,那么一种可能的优化是也用c编写绘图代码,并让它与Chipmunk直接交互。这样一来,它可以比任何通用包装解决方案更具性能,因为它将跳过整个层。

  • 在许多情况下,一个完整的游戏/应用程序的瓶颈不在物理包装中。如果你的游戏有人工智能、逻辑等等在python中,那么ctype增加的包装器开销相比之下也没那么差。

  • PYPYPyPy上的CTYPE有可能非常快。然而,目前在使用PyPy-1.9时,在PyPy上的黑猩猩速度实际上比在cpython上慢一点。希望这在未来会有所改善。

请注意,从2007年底开始,金龟子就已经存在了,这意味着并不是现在存在的所有包装选项都存在,或者在一开始不够稳定/完整,不足以供金龟子使用。现在有更多的选项可用,使用ctype并不是一成不变的。如果有更好的替代方案出现,那么考虑到改进的程度足够大,金色鼠可能会改用。

代码布局

Pymunk的大部分应该是相当直截了当的。

除了记录的API之外,Pymunk还有几个有趣的部分。低级绑定到Chipmunk,一个定制的文档生成扩展和一个定制的setup.py文件,允许编译Chipmunk。

docs/src/ext/autoexample.py

扫描目录并提取顶层文档字符串的Sphinx扩展。用于自动生成示例文档。

pymunk/_callbacks.py

回调不能在类上指定,因此它们都聚集在这里。

pymunk/_chipmunk_cffi.py

该文件只包含对_cfi_ackend.py的调用,并且主要作为包装器存在,以便能够在CFFI的ABI和API模式之间切换。目前发布的代码中没有使用它,但在实验中使用了它。

pymunk/pymunk_extension_build.py

低级Chipmunk绑定位于此文件中。包含如何通过CFFI将Chipmunk2D构建到PYD文件中的配置。

setup.py

除了标准的安装内容之外,这个文件还包含定制的构建命令,以便使用Build_ext扩展从源代码构建Chipmunk。

金龟子/范例/*

Pymunk用法例集。试图展示Pymunk最常见的特征。

金龟子/测试/*

(单元)测试的集合。没有涵盖所有情况,但大多数核心内容都在那里。这些测试需要一个工作正常的Chipmunk库文件。

pymunk_cffi/*

Parmunk使用的Chipmunk2D的自定义(c源代码和标题)扩展。将在CFFI构建PYD扩展时使用。

工具/*

可用于各种开发任务(如生成文档)的帮助器脚本集合。

测试

Pymunk.test包中包含了许多单元测试(pymunk/test)。并不是所有的代码都经过了测试,但大部分代码(在撰写本文时,大约85%的核心部分)都经过了测试。

这些测试可以通过调用模块::

> python -m pymunk.tests

通过指定筛选参数,可以控制要运行哪些测试。匹配的范围尽可能广,所以 UnitTest 匹配所有单元测试, test_arbiter 中的所有测试 test_arbiter.pytestResetitution 完全匹配 testRestitution 测试案例::

> python -m pymunk.tests -f testRestitution

要查看测试命令的所有选项,请使用-h::

> python -m pymunk.tests -h

由于测试甚至包括可选部分,因此您要么必须确保安装了所有可选依赖项,要么过滤掉那些测试。

处理Chipmunk的非包裹部分

如果您需要使用Chipmunk中存在但当前不包括在Chipmunk中的内容,最简单的方法是手动添加。

例如,让我们假设身体的is_sleing属性不是由Pymunk包装的。获取此属性的Chipmunk方法名为cpBodyIsSleping。

首先,我们需要检查它是否包含在PYMUNK_EXTENSION_Build.py中的cdef定义中。如果它不是简单地添加它。

cpBool cpBodyIsSleeping(const cpBody *body);

然后,为了使其易于使用,我们想要创建一个不错的python方法::

def is_sleeping(body):
    return cp.cpBodyIsSleeping(body._body)

现在我们已经准备好映射并准备使用我们的新方法。

请注意,任何cdef方法都不是公共API的一部分,因此可能会在Pymunk的次要或补丁版本之间发生变化。

弱引用和自由方法

在内部,Pymunk分配来自Chipmunk(c库)的结构。例如,在创建pymunk.Body时,将从构造函数方法内部创建Body结构。正因为如此,重要的是当不再需要时,适当地释放相应的c端内存,通常是在对Python端对象进行垃圾回收时。大多数Pymunk对象使用 ffi.gc 有一个自定义的免费功能来完成这项工作。请注意,释放的顺序对于避免错误非常重要。