Chipmunk约束:cpConstraint

约束是用来描述两个刚体如何相互作用的(他们是如何约束彼此的)。约束可以是允许刚体像我们身体的骨头一样轴转动的简单关节,也可以是更抽象的比如齿轮关节或马达关节。

约束是什么,不是什么

在Chipmunk中,约束都是基于速度的约束。这意味着他们主要通过同步两个刚体的速度进行作用。一个轴关节将两个独立刚体的两个锚点连接起来,公式定义要求两个锚点的速度必须相同并且计算施加在刚体上的冲量以便试图保持这个状态。约束将速度视为主要的输入并且产生一个速度变化作为它的输出。一些约束(尤其是关节)通过改变速度来修正位置的差异。更多详情见下一节。

连接两个刚体的弹簧不是一个约束。它很像约束因为它会创建一个力来影响两个刚体的速度,但是弹簧将距离作为输入,将力作为输出。如果弹簧不是一个约束,你会问为什么还会有两种类型的弹簧约束。原因是他们是阻尼弹簧。弹簧关联的阻尼才是真正的约束,这个约束会根据关联的两个刚体的相对速度来创建速度的变化。因为大部分情况将一个阻尼器和一个弹簧放在一起很方便,我想我还不如将弹簧力作为约束的一部分,而不是用一个阻尼器约束然后让用户单独计算和施加弹簧力。

属性

  • 得到约束关联的两个刚体
  1. cpBody * cpConstraintGetA(const cpConstraint *constraint)
  2. cpBody * cpConstraintGetB(const cpConstraint *constraint)
  • 约束能够作用于两个刚体的最大力。默认为INFINITY
  1. cpFloat cpConstraintGetMaxForce(const cpConstraint *constraint)
  2. void cpConstraintSetMaxForce(cpConstraint *constraint, cpFloat value)
  • 关节误差百分比用来维系一秒后的不固定。这和碰撞偏差机制完全一样,但是这会修正关节的误差而不是重叠碰撞。
  1. cpFloat cpConstraintGetErrorBias(const cpConstraint *constraint)
  2. void cpConstraintSetErrorBias(cpConstraint *constraint, cpFloat value)
  • 约束可以纠错的最大速度。默认为INFINITY
  1. cpFloat cpConstraintGetMaxBias(const cpConstraint *constraint)
  2. void cpConstraintSetMaxBias(cpConstraint *constraint, cpFloat value)
  • 得到约束被添加进去的空间
  1. cpSpace* cpConstraintGetSpace(const cpConstraint *constraint)
  • 使用数据指针。使用指针来从回调中得到拥有该约束的游戏对象的一个引用。
  1. cpDataPointer cpConstraintGetUserData(const cpConstraint *constraint)
  2. void cpConstraintSetUserData(cpConstraint *constraint, cpDataPointer value)
  • 约束被施加的最新的冲量。为了转化成力,除以传进cpSpaceStep()的时间步。你可以使用这点来检查施加的力是否超过了一定的阈值从而实现可断裂的关节。

  • 断裂关节例子

  1. // 创建关节且设置最大力属性
  2. breakableJoint = cpSpaceAddConstraint(space, cpPinJointNew(body1, body2, cpv(15,0), cpv(-15,0)));
  3. cpConstraintSetMaxForce(breakableJoint, 4000);
  4. // 在update函数中,正常步进模拟空间...
  5. cpFloat dt = 1.0/60.0;
  6. cpSpaceStep(space, dt);
  7. if(breakableJoint){
  8. // 将冲量除以时间步得到施加的力
  9. cpFloat force = cpConstraintGetImpulse(breakableJoint)/dt;
  10. cpFloat maxForce = cpConstraintGetMaxForce(breakableJoint);
  11. // 如果该力大于设定的阈值则断裂关节
  12. if(force > 0.9*maxForce){
  13. cpSpaceRemoveConstraint(space, breakableJoint);
  14. breakableJoint = NULL;
  15. }
  16. }

要访问特定关节类型的属性,使用提供的存取器函数(如cpPinJointGetAnchr1())。查看属性列表来获得更多的信息。

反馈纠错

Chipmunk的关节并不完美。销关节并不能维系两个锚点之间确切正确的距离,枢轴关节同样也不能保持关联的锚点完全在一起。他们被设计通过自纠错来处理这个问题。在Chipmunk5中,我们有很多额外的控制来实现关节对自身的纠错,甚至可以使用这个特性,以独特的方式使用关节来创建一些物理效果。

  • 伺服马达:如 打开/关闭门或者旋转物件,无需用最大的力
  • 起货机:朝着另外一个物体拉一个物体无需用最大的力
  • 鼠标操作:自如的以粗暴、摇晃的鼠标输入方式来与物体交互

cpConstraint结构体有3个属性控制着误差纠正,maxForce,maxBias以及biasCoef.maxForce — to be done

  1. // Faked top down friction.
  2. // A pivot joint configured this way will calculate friction against the ground for games with a top down perspective.
  3. // Because the joint correction is disabled, the joint will not recenter itself and only apply to the velocity.
  4. // The force the joint applies when changing the velocity will be clamped by the max force
  5. // and this causes it to work exactly like friction!
  6. cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, body, cpvzero, cpvzero));
  7. pivot->maxBias = 0.0f; // disable joint correction
  8. pivot->maxForce = 1000.0f;
  9. // The pivot joint doesn't apply rotational forces, use a gear joint with a ratio of 1.0 for that.
  10. cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(staticBody, body, 0.0f, 1.0f));
  11. gear->maxBias = 0.0f; // disable joint correction
  12. gear->maxForce = 5000.0f;
  13. // Also, instead of connecting the joints to a static body, you can connect them to an infinite mass rogue body.
  14. // You can then use the rogue body as a control body to the connected body. See the Tank demo as an example.

约束和碰撞形状

约束和碰撞形状互不了解双方信息。当为刚体连接关节时,锚点不必处于刚体形状的内部,这么做通常是有意义的。同样的,为两个刚体添加约束并不能阻止刚体形状碰撞。事实上,这便是碰撞组属性存在的主要原因。

现有关节类型视频演示

视频下载—》优酷

共享内存管理函数

DestroyFree函数由所有关节类型共享。Allocationinit函数对于每种关节类型都是特定的。