札记

Chipmunk直到 6.1.2 版本才支持线段、线段碰撞。由于兼容性的原因,你必须明确地全局调用cpEnableSegmentToSegmentCollisions()来启用它们。 (感谢LegoCylon对此的帮助)

属性

Chipmunk为一些碰撞形状属性提供了getter/ setter函数。如果形状关联的刚体在休眠,设置大多数属性会自动唤醒它们。如果你想的话,也可以直接设置cpShape结构的某些字段。他们在头文件中都记录有。

  1. cpBody * cpShapeGetBody(const cpShape *shape)
  2. void cpShapeSetBody(cpShape *shape, cpBody *body)

只有当形状尚未添加进空间中的时候才能关联到一个刚体。

  1. cpBB cpShapeGetBB(const cpShape *shape)

上面得到的是形状的碰撞包围盒。只能保证在cpShapeCacheBB()cpSpaceStep()调用后是有效的。移动形状所连接到刚体并不更新它的包围盒。对于没有关联到刚体的用于查询的形状,也可以使用cpShapeUpdate()

  1. cpBool cpShapeGetSensor(const cpShape *shape)
  2. void cpShapeSetSensor(cpShape *shape, cpBool value)

用来标识形状是否是一个感应器的布尔值。感应器只调用碰撞回调,但却不产生真实的碰撞。

  1. cpFloat cpShapeGetElasticity(const cpShape *shape)
  2. void cpShapeSetElasticity(cpShape *shape, cpFloat value)

上面说的是形状的弹性。值0.0表示没有反弹,而值为1.0将提供一个“完美”的反弹。然而由于使用1.0或更高的值会导致模拟不精确,所以不推荐。碰撞的弹性是由单个形状的弹性相乘得到。

  1. cpFloat cpShapeGetFriction(const cpShape *shape)
  2. void cpShapeSetFriction(cpShape *shape, cpFloat value)

上面说的是摩擦系数。Chipmunk使用的是库仑摩擦力模型,0.0值表示无摩擦。碰撞间的摩擦是由单个形状的摩擦相乘找到。摩擦系数表

  1. cpVect cpShapeGetSurfaceVelocity(const cpShape *shape)
  2. void cpShapeSetSurfaceVelocity(cpShape *shape, cpVect value)

上面说的是物体的表面速度。可用于创建传送带或走动的玩家。此值在计算摩擦时才会使用,而不是用于解决碰撞。

  1. cpCollisionType cpShapeGetCollisionType(const cpShape *shape)
  2. void cpShapeSetCollisionType(cpShape *shape, cpCollisionType value)

您可以为Chipmunk的碰撞形状指定类型从而在接触特定类型物体的时候触发回调。更多信息请参见回调部分。

  1. cpGroup cpShapeGetGroup(const cpShape *shape)
  2. void cpShapeSetGroup(cpShape *shape, cpGroup value)

在相同的非零组中,形状间不产生碰撞。在创建了一个许多形状组成的物体,但却不想自身与自身之间发生碰撞,这会很有用。默认值为CP_NO_GROUP

  1. cpLayers cpShapeGetLayers(const cpShape *shape)
  2. void cpShapeSetLayers(cpShape *shape, cpLayers value)

只有在相同的位平面内形状间才发生碰撞。比如(a->layers & b->layers) != 0。默认情况下,一个形状占据所有的位平面。如果你不熟悉如何使用它们,维基百科有篇很好的文章#top)介绍了位掩码的相关知识你可以阅读下。默认值为CP_ALL_LAYERS。

  1. cpSpace* cpShapeGetSpace(const cpShape *shape)

得到形状被添加进去的空间。

  1. cpDataPointer cpShapeGetUserData(const cpShape *shape)
  2. void cpShapeSetUserData(cpShape *shape, cpDataPointer value)

上面说的是用户定义的数据指针。如果你设置将其指向形状关联的游戏对象,那么你可以从Chipmunk回调中访问你的的游戏对象。

碰撞过滤

Chipmunk 有两种主要的途径来忽略碰撞: 群组和层

群组是为了忽略一个复杂对象部分之间的碰撞。玩偶是一个很好的例子。当联合手臂到躯干的时候,他们可以重叠。群组允许这样做。相同群组间的形状不产生碰撞。所以通过将一个布娃娃的所有形状放在在同一群组中,就会阻止其碰撞自身的其它部件。

层允许你将碰撞的形状分离在相互排斥的位面。形状不止可以在一个层上,形状与形状发生碰撞,而两者必须至少在一个相同的层上。举一个简单的例子,比如说形状A是在第1层,形状B是在第2层和形状C是在层1和2 。形状A和B不会互相碰撞,但形状C将与这两个A和B发生碰撞

层也可以用于建立基于碰撞的规则。比如说在你的游戏中有四种类型的形状。玩家,敌人,玩家子弹,敌人子弹。玩家应该和敌人发生碰撞,但子弹却不应该和发射者碰撞。图表类似下图:

Player Enemy Player Bullet Enemy Bullet
Player - (1) (2)
Enemy - - (3)
Player Bullet - - -
Enemy Bullet - - - -

图表中‘-’是多余的斑点,数字的地方应该发生碰撞。您可以使用层要定义每个规则。然后将层添加到每个类型:玩家应该在层1和2,敌人应该是在层1和3中,玩家的子弹应该是在层3中,以及敌人的子弹应该是在层2中。这种处理层作为为规则的方式,可以定义多达32个规则。默认cpLayers类型为unsigned int其中在大多数系统是32位的。如果你需要更多的比特来完成工作, 你可以在chipmunk_types.h中重新定义cpLayers类型。

还有最后一个方法通过碰撞处理函数来过滤碰撞。见回调的部分来获取更多信息。碰撞处理程序可以更灵活,但它们也是最慢的方法。所以,你要优先尝试使用群组或层。

内存管理函数

  1. void cpShapeDestroy(cpShape *shape)
  2. void cpShapeFree(cpShape *shape)

DestroyFree函数由所有形状类型共享。分配和初始化函数特定于每一个形状。见下文。

其他函数

  • cpBB cpShapeCacheBB(cpShape *shape) – 同步形状与形状关联的刚体
  • cpBB cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot) – 设置形状的位置和旋转角度
  • void cpResetShapeIdCounter(void) –Chipmunk使用了一个计数器,以便每一个新的形状是在空间索引中使用唯一的哈希值。因为这会影响空间中碰撞被发现和处理的顺序,你可以在每次在空间中添加新的形状时重置形状计数器。如果你不这样做,有可能模拟(非常)略有不同。

圆形形状

  1. cpCircleShape *cpCircleShapeAlloc(void)
  2. cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)
  3. cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)

body 是圆形形状关联的刚体。offset 是在刚体局部坐标系内与刚体中心的偏移量。

  1. cpVect cpCircleShapeGetOffset(cpShape *circleShape)
  2. cpFloat cpCircleShapeGetRadius(cpShape *circleShape)

圆形形状属性的getter函数。传一个非圆形形状将会抛出一个异常。

线段形状

多边形形状

修改cpShpaes

简短的回答是,你不能因为这些更改将只拿起一个改变形状的面的位置,而不是它的速度。长的答案是,你可以使用“不安全”的API,只要你认识到这样做会不会导致真实的物理行为。这些额外的功能都在一个单独的头chipmunk_unsafe.h定义。

札记

  • 你可以将多个碰撞形状关联到刚体上。这样你就可以创建几乎任何形状。
  • 关联在同一个刚体上的形状不会产生冲突。你不必担心同个刚体上的形状的重叠问题。
  • 确保刚体和刚体的碰撞形状都被添加进了空间。有个例外,就是当你如果有一个外部刚体或你嵌入自身到刚体。在这种情况下,只把形状添加进空间。(to be done)