|
@@ -0,0 +1,1073 @@
|
|
|
+package tamias
|
|
|
+
|
|
|
+var CONSTRAINT_BIAS_COEF = Float(0.1);
|
|
|
+
|
|
|
+type Constraint interface {
|
|
|
+ A() (*Body)
|
|
|
+ B() (*Body)
|
|
|
+ Data() (interface{})
|
|
|
+
|
|
|
+ MaxForce() (Float)
|
|
|
+ BiasCoef() (Float)
|
|
|
+ MaxBias() (Float)
|
|
|
+
|
|
|
+ PreStep(dt, dt_inv int)
|
|
|
+ ApplyImpulse()
|
|
|
+ GetImpulse() (Float)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+type constraint struct {
|
|
|
+ a, b *Body;
|
|
|
+ maxForce, biasCoef, maxBias Float;
|
|
|
+ data interface{}
|
|
|
+}
|
|
|
+
|
|
|
+type BasicConstraint constraint
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func (c * constraint) Bodies() (*Body, *Body) {
|
|
|
+ return c.a, c.b
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (c * constraint) MaxForce() (Float) {
|
|
|
+ return c.maxForce
|
|
|
+}
|
|
|
+
|
|
|
+func (c * constraint) BiasCoef() (Float) {
|
|
|
+ return c.biasCoef
|
|
|
+}
|
|
|
+
|
|
|
+func (c * constraint) MaxBias() (Float) {
|
|
|
+ return c.maxBias
|
|
|
+}
|
|
|
+
|
|
|
+func (c * constraint) Init(a, b *Body) (* constraint) {
|
|
|
+ c.a = a
|
|
|
+ c.b = b
|
|
|
+ c.maxForce = INFINITY
|
|
|
+ c.biasCoef = CONSTRAINT_BIAS_COEF
|
|
|
+ c.maxBias = INFINITY
|
|
|
+ return c
|
|
|
+}
|
|
|
+
|
|
|
+type SpringConstraint interface {
|
|
|
+ Constraint
|
|
|
+ SpringTorque(Vect) (Float)
|
|
|
+}
|
|
|
+
|
|
|
+type DampedRotarySpring struct {
|
|
|
+ constraint
|
|
|
+ restAngle , stiffness , damping Float
|
|
|
+ dt , target_wrn, iSum Float
|
|
|
+}
|
|
|
+
|
|
|
+type DampedSpring struct {
|
|
|
+ constraint
|
|
|
+ anchr1, anchr2 Vect
|
|
|
+ restLength, stiffness, damping Float;
|
|
|
+ dt, target_vrn Float
|
|
|
+ r1, r2 Vect
|
|
|
+ nMass Float;
|
|
|
+ n Vect;
|
|
|
+}
|
|
|
+
|
|
|
+type GearJoint struct {
|
|
|
+ constraint
|
|
|
+ phase, ratio, ratio_inv, iSum Float
|
|
|
+ bias, jAcc, jMax Float
|
|
|
+}
|
|
|
+
|
|
|
+type GrooveJoint struct {
|
|
|
+ constraint
|
|
|
+ grv_n, grv_a, grv_b Vect
|
|
|
+ anchr2 Vect
|
|
|
+ grv_tn Vect
|
|
|
+ clamp Float
|
|
|
+ r1, r2 Vect
|
|
|
+ k1, k2 Vect
|
|
|
+
|
|
|
+ jAcc Vect
|
|
|
+ jMaxLen Vect
|
|
|
+ bias Vect
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+type PinJoint struct {
|
|
|
+ constraint
|
|
|
+ anchr1, anchr2 Vect
|
|
|
+ dist Float
|
|
|
+ r1, r2 Vect
|
|
|
+ n Vect
|
|
|
+ nMass Float
|
|
|
+ jnAcc, jnMax Float
|
|
|
+ bias Float
|
|
|
+}
|
|
|
+
|
|
|
+type PivotJoint struct {
|
|
|
+ constraint
|
|
|
+ anchr1, anchr2 Vect
|
|
|
+ r1, r2 Vect
|
|
|
+ k1, k2 Vect
|
|
|
+
|
|
|
+ jAcc Vect
|
|
|
+ jMaxLen Float
|
|
|
+ bias Vect
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+type RatchetJoint struct {
|
|
|
+ constraint
|
|
|
+ angle, phase, ratchet Float
|
|
|
+ iSum Float
|
|
|
+ bias Float
|
|
|
+ jAcc, jMax Float
|
|
|
+}
|
|
|
+
|
|
|
+type RotaryLimitJoint struct {
|
|
|
+ constraint
|
|
|
+ min, max Float;
|
|
|
+ iSum Float;
|
|
|
+ bias Float;
|
|
|
+ jAcc, jMax Float;
|
|
|
+}
|
|
|
+
|
|
|
+type SimpleMotor struct {
|
|
|
+ constraint
|
|
|
+ rate, iSum, jAcc, jMax Float;
|
|
|
+}
|
|
|
+
|
|
|
+type SlideJoint struct {
|
|
|
+ constraint
|
|
|
+ anchr1, anchr2 Vect;
|
|
|
+ min, max Float;
|
|
|
+
|
|
|
+ r1, r2 Vect;
|
|
|
+ n Vect;
|
|
|
+ nMass Float;
|
|
|
+
|
|
|
+ jnAcc, jnMax Float;
|
|
|
+ bias Float;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (spring * DampedRotarySpring) SpringTorque(relativeAngle Float) (Float) {
|
|
|
+ return (relativeAngle - spring.restAngle)*spring.stiffness;
|
|
|
+}
|
|
|
+
|
|
|
+func (spring * DampedRotarySpring) PreStep(dt, dt_inv Float) {
|
|
|
+ a, b := spring.Bodies()
|
|
|
+ spring.iSum = Float(1.0)/(a.i_inv + b.i_inv);
|
|
|
+ spring.dt = dt;
|
|
|
+ spring.target_wrn = Float(0.0);
|
|
|
+
|
|
|
+ da := a.a - b.a
|
|
|
+ j_spring := spring.SpringTorque(da) * dt
|
|
|
+ a.w -= j_spring * a.i_inv;
|
|
|
+ b.w += j_spring * b.i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func (spring * DampedRotarySpring) ApplyImpulse() {
|
|
|
+
|
|
|
+ a, b := spring.Bodies()
|
|
|
+
|
|
|
+ wrn := a.w - b.w;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ w_aid := (-spring.damping*spring.dt/spring.iSum).Exp()
|
|
|
+ w_damp := wrn*(Float(1.0) - w_aid);
|
|
|
+ spring.target_wrn = wrn - w_damp;
|
|
|
+
|
|
|
+
|
|
|
+ j_damp := w_damp*spring.iSum;
|
|
|
+ a.w -= j_damp*a.i_inv;
|
|
|
+ b.w += j_damp*b.i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+func (spring * DampedRotarySpring) GetImpulse() (Float) {
|
|
|
+ return Float(0.0)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func DampedRotarySpringAlloc() (* DampedRotarySpring) {
|
|
|
+ return &DampedRotarySpring{}
|
|
|
+}
|
|
|
+
|
|
|
+func (spring * DampedRotarySpring) Init(a, b *Body, restAngle, stiffness,
|
|
|
+ damping Float) (* DampedRotarySpring) {
|
|
|
+
|
|
|
+ spring.constraint.Init(a, b)
|
|
|
+ spring.restAngle = restAngle
|
|
|
+ spring.stiffness = stiffness
|
|
|
+ spring.damping = damping
|
|
|
+ return spring
|
|
|
+}
|
|
|
+
|
|
|
+func DampedRotarySpringNew(a, b *Body, restAngle, stiffness,
|
|
|
+ damping Float) (* DampedRotarySpring) {
|
|
|
+ return DampedRotarySpringAlloc().Init(a, b, restAngle, stiffness, damping)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+defaultSpringForce(cpDampedSpring *spring, cpFloat dist){
|
|
|
+ return (spring->restLength - dist)*spring->stiffness;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = spring->constraint.a;
|
|
|
+ cpBody *b = spring->constraint.b;
|
|
|
+
|
|
|
+ spring->r1 = cpvrotate(spring->anchr1, a->rot);
|
|
|
+ spring->r2 = cpvrotate(spring->anchr2, b->rot);
|
|
|
+
|
|
|
+ cpVect delta = cpvsub(cpvadd(b->p, spring->r2), cpvadd(a->p, spring->r1));
|
|
|
+ cpFloat dist = cpvlength(delta);
|
|
|
+ spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
|
|
|
+
|
|
|
+
|
|
|
+ spring->nMass = 1.0f/k_scalar(a, b, spring->r1, spring->r2, spring->n);
|
|
|
+
|
|
|
+ spring->dt = dt;
|
|
|
+ spring->target_vrn = 0.0f;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist);
|
|
|
+ apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, f_spring*dt));
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpDampedSpring *spring)
|
|
|
+{
|
|
|
+ cpBody *a = spring->constraint.a;
|
|
|
+ cpBody *b = spring->constraint.b;
|
|
|
+
|
|
|
+ cpVect n = spring->n;
|
|
|
+ cpVect r1 = spring->r1;
|
|
|
+ cpVect r2 = spring->r2;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat vrn = normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat v_damp = -vrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->nMass));
|
|
|
+ spring->target_vrn = vrn + v_damp;
|
|
|
+
|
|
|
+ apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpConstraint *constraint)
|
|
|
+{
|
|
|
+ return 0.0f;
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpDampedSpring)
|
|
|
+
|
|
|
+cpDampedSpring *
|
|
|
+cpDampedSpringAlloc(void)
|
|
|
+{
|
|
|
+ return (cpDampedSpring *)cpmalloc(sizeof(cpDampedSpring));
|
|
|
+}
|
|
|
+
|
|
|
+cpDampedSpring *
|
|
|
+cpDampedSpringInit(cpDampedSpring *spring, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)spring, cpDampedSpringGetClass(), a, b);
|
|
|
+
|
|
|
+ spring->anchr1 = anchr1;
|
|
|
+ spring->anchr2 = anchr2;
|
|
|
+
|
|
|
+ spring->restLength = restLength;
|
|
|
+ spring->stiffness = stiffness;
|
|
|
+ spring->damping = damping;
|
|
|
+ spring->springForceFunc = (cpDampedSpringForceFunc)defaultSpringForce;
|
|
|
+
|
|
|
+ return spring;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpDampedSpringInit(cpDampedSpringAlloc(), a, b, anchr1, anchr2, restLength, stiffness, damping);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpGearJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ joint->iSum = 1.0f/(a->i_inv*joint->ratio_inv + joint->ratio*b->i_inv);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat maxBias = joint->constraint.maxBias;
|
|
|
+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(b->a*joint->ratio - a->a - joint->phase), -maxBias, maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jMax = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat j = joint->jAcc;
|
|
|
+ a->w -= j*a->i_inv*joint->ratio_inv;
|
|
|
+ b->w += j*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpGearJoint *joint)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat wr = b->w*joint->ratio - a->w;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat j = (joint->bias - wr)*joint->iSum;
|
|
|
+ cpFloat jOld = joint->jAcc;
|
|
|
+ joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);
|
|
|
+ j = joint->jAcc - jOld;
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= j*a->i_inv*joint->ratio_inv;
|
|
|
+ b->w += j*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpGearJoint *joint)
|
|
|
+{
|
|
|
+ return cpfabs(joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpGearJoint)
|
|
|
+
|
|
|
+cpGearJoint *
|
|
|
+cpGearJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpGearJoint *)cpmalloc(sizeof(cpGearJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpGearJoint *
|
|
|
+cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->phase = phase;
|
|
|
+ joint->ratio = ratio;
|
|
|
+ joint->ratio_inv = 1.0f/ratio;
|
|
|
+
|
|
|
+ joint->jAcc = 0.0f;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpGearJointInit(cpGearJointAlloc(), a, b, phase, ratio);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+cpGearJointSetRatio(cpConstraint *constraint, cpFloat value)
|
|
|
+{
|
|
|
+ cpConstraintCheckCast(constraint, cpGearJoint);
|
|
|
+ ((cpGearJoint *)constraint)->ratio = value;
|
|
|
+ ((cpGearJoint *)constraint)->ratio_inv = 1.0f/value;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpGrooveJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ cpVect ta = cpBodyLocal2World(a, joint->grv_a);
|
|
|
+ cpVect tb = cpBodyLocal2World(a, joint->grv_b);
|
|
|
+
|
|
|
+
|
|
|
+ cpVect n = cpvrotate(joint->grv_n, a->rot);
|
|
|
+ cpFloat d = cpvdot(ta, n);
|
|
|
+
|
|
|
+ joint->grv_tn = n;
|
|
|
+ joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat td = cpvcross(cpvadd(b->p, joint->r2), n);
|
|
|
+
|
|
|
+ if(td <= cpvcross(ta, n)){
|
|
|
+ joint->clamp = 1.0f;
|
|
|
+ joint->r1 = cpvsub(ta, a->p);
|
|
|
+ } else if(td >= cpvcross(tb, n)){
|
|
|
+ joint->clamp = -1.0f;
|
|
|
+ joint->r1 = cpvsub(tb, a->p);
|
|
|
+ } else {
|
|
|
+ joint->clamp = 0.0f;
|
|
|
+ joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jMaxLen = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
|
|
+ joint->bias = cpvclamp(cpvmult(delta, -joint->constraint.biasCoef*dt_inv), joint->constraint.maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static inline cpVect
|
|
|
+grooveConstrain(cpGrooveJoint *joint, cpVect j){
|
|
|
+ cpVect n = joint->grv_tn;
|
|
|
+ cpVect jClamp = (joint->clamp*cpvcross(j, n) > 0.0f) ? j : cpvproject(j, n);
|
|
|
+ return cpvclamp(jClamp, joint->jMaxLen);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpGrooveJoint *joint)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ cpVect r1 = joint->r1;
|
|
|
+ cpVect r2 = joint->r2;
|
|
|
+
|
|
|
+
|
|
|
+ cpVect vr = relative_velocity(a, b, r1, r2);
|
|
|
+
|
|
|
+ cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);
|
|
|
+ cpVect jOld = joint->jAcc;
|
|
|
+ joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j));
|
|
|
+ j = cpvsub(joint->jAcc, jOld);
|
|
|
+
|
|
|
+
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, j);
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpGrooveJoint *joint)
|
|
|
+{
|
|
|
+ return cpvlength(joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpGrooveJoint)
|
|
|
+
|
|
|
+cpGrooveJoint *
|
|
|
+cpGrooveJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpGrooveJoint *)cpmalloc(sizeof(cpGrooveJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpGrooveJoint *
|
|
|
+cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->grv_a = groove_a;
|
|
|
+ joint->grv_b = groove_b;
|
|
|
+ joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));
|
|
|
+ joint->anchr2 = anchr2;
|
|
|
+
|
|
|
+ joint->jAcc = cpvzero;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpPinJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ joint->r1 = cpvrotate(joint->anchr1, a->rot);
|
|
|
+ joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
|
|
+
|
|
|
+ cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
|
|
+ cpFloat dist = cpvlength(delta);
|
|
|
+ joint->n = cpvmult(delta, 1.0f/(dist ? dist : (cpFloat)INFINITY));
|
|
|
+
|
|
|
+
|
|
|
+ joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat maxBias = joint->constraint.maxBias;
|
|
|
+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(dist - joint->dist), -maxBias, maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jnMax = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ cpVect j = cpvmult(joint->n, joint->jnAcc);
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, j);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpPinJoint *joint)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+ cpVect n = joint->n;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat vrn = normal_relative_velocity(a, b, joint->r1, joint->r2, n);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat jn = (joint->bias - vrn)*joint->nMass;
|
|
|
+ cpFloat jnOld = joint->jnAcc;
|
|
|
+ joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, joint->jnMax);
|
|
|
+ jn = joint->jnAcc - jnOld;
|
|
|
+
|
|
|
+
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpPinJoint *joint)
|
|
|
+{
|
|
|
+ return cpfabs(joint->jnAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpPinJoint);
|
|
|
+
|
|
|
+
|
|
|
+cpPinJoint *
|
|
|
+cpPinJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpPinJoint *)cpmalloc(sizeof(cpPinJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpPinJoint *
|
|
|
+cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->anchr1 = anchr1;
|
|
|
+ joint->anchr2 = anchr2;
|
|
|
+
|
|
|
+ cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot));
|
|
|
+ cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot));
|
|
|
+ joint->dist = cpvlength(cpvsub(p2, p1));
|
|
|
+
|
|
|
+ joint->jnAcc = 0.0f;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ joint->r1 = cpvrotate(joint->anchr1, a->rot);
|
|
|
+ joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
|
|
+
|
|
|
+
|
|
|
+ k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jMaxLen = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
|
|
+ joint->bias = cpvclamp(cpvmult(delta, -joint->constraint.biasCoef*dt_inv), joint->constraint.maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpPivotJoint *joint)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ cpVect r1 = joint->r1;
|
|
|
+ cpVect r2 = joint->r2;
|
|
|
+
|
|
|
+
|
|
|
+ cpVect vr = relative_velocity(a, b, r1, r2);
|
|
|
+
|
|
|
+
|
|
|
+ cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);
|
|
|
+ cpVect jOld = joint->jAcc;
|
|
|
+ joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->jMaxLen);
|
|
|
+ j = cpvsub(joint->jAcc, jOld);
|
|
|
+
|
|
|
+
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, j);
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpConstraint *joint)
|
|
|
+{
|
|
|
+ return cpvlength(((cpPivotJoint *)joint)->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpPivotJoint)
|
|
|
+
|
|
|
+cpPivotJoint *
|
|
|
+cpPivotJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpPivotJoint *)cpmalloc(sizeof(cpPivotJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpPivotJoint *
|
|
|
+cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->anchr1 = anchr1;
|
|
|
+ joint->anchr2 = anchr2;
|
|
|
+
|
|
|
+ joint->jAcc = cpvzero;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, anchr1, anchr2);
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
|
|
|
+{
|
|
|
+ return cpPivotJointNew2(a, b, cpBodyWorld2Local(a, pivot), cpBodyWorld2Local(b, pivot));
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ cpFloat angle = joint->angle;
|
|
|
+ cpFloat phase = joint->phase;
|
|
|
+ cpFloat ratchet = joint->ratchet;
|
|
|
+
|
|
|
+ cpFloat delta = b->a - a->a;
|
|
|
+ cpFloat diff = angle - delta;
|
|
|
+ cpFloat pdist = 0.0f;
|
|
|
+
|
|
|
+ if(diff*ratchet > 0.0f){
|
|
|
+ pdist = diff;
|
|
|
+ } else {
|
|
|
+ joint->angle = cpffloor((delta - phase)/ratchet)*ratchet + phase;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ joint->iSum = 1.0f/(a->i_inv + b->i_inv);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat maxBias = joint->constraint.maxBias;
|
|
|
+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*pdist, -maxBias, maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jMax = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ if(!joint->bias)
|
|
|
+ joint->jAcc = 0.0f;
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= joint->jAcc*a->i_inv;
|
|
|
+ b->w += joint->jAcc*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpRatchetJoint *joint)
|
|
|
+{
|
|
|
+ if(!joint->bias) return;
|
|
|
+
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat wr = b->w - a->w;
|
|
|
+ cpFloat ratchet = joint->ratchet;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat j = -(joint->bias + wr)*joint->iSum;
|
|
|
+ cpFloat jOld = joint->jAcc;
|
|
|
+ joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, joint->jMax*cpfabs(ratchet))/ratchet;
|
|
|
+ j = joint->jAcc - jOld;
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= j*a->i_inv;
|
|
|
+ b->w += j*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpRatchetJoint *joint)
|
|
|
+{
|
|
|
+ return cpfabs(joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpRatchetJoint)
|
|
|
+
|
|
|
+cpRatchetJoint *
|
|
|
+cpRatchetJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpRatchetJoint *)cpmalloc(sizeof(cpRatchetJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpRatchetJoint *
|
|
|
+cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->angle = 0.0f;
|
|
|
+ joint->phase = phase;
|
|
|
+ joint->ratchet = ratchet;
|
|
|
+
|
|
|
+ joint->angle = b->a - a->a;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpRatchetJointInit(cpRatchetJointAlloc(), a, b, phase, ratchet);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ cpFloat dist = b->a - a->a;
|
|
|
+ cpFloat pdist = 0.0f;
|
|
|
+ if(dist > joint->max) {
|
|
|
+ pdist = joint->max - dist;
|
|
|
+ } else if(dist < joint->min) {
|
|
|
+ pdist = joint->min - dist;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ joint->iSum = 1.0f/(a->i_inv + b->i_inv);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat maxBias = joint->constraint.maxBias;
|
|
|
+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jMax = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ if(!joint->bias)
|
|
|
+ joint->jAcc = 0.0f;
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= joint->jAcc*a->i_inv;
|
|
|
+ b->w += joint->jAcc*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpRotaryLimitJoint *joint)
|
|
|
+{
|
|
|
+ if(!joint->bias) return;
|
|
|
+
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat wr = b->w - a->w;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat j = -(joint->bias + wr)*joint->iSum;
|
|
|
+ cpFloat jOld = joint->jAcc;
|
|
|
+ if(joint->bias < 0.0f){
|
|
|
+ joint->jAcc = cpfclamp(jOld + j, 0.0f, joint->jMax);
|
|
|
+ } else {
|
|
|
+ joint->jAcc = cpfclamp(jOld + j, -joint->jMax, 0.0f);
|
|
|
+ }
|
|
|
+ j = joint->jAcc - jOld;
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= j*a->i_inv;
|
|
|
+ b->w += j*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpRotaryLimitJoint *joint)
|
|
|
+{
|
|
|
+ return cpfabs(joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpRotaryLimitJoint)
|
|
|
+
|
|
|
+cpRotaryLimitJoint *
|
|
|
+cpRotaryLimitJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpRotaryLimitJoint *)cpmalloc(sizeof(cpRotaryLimitJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpRotaryLimitJoint *
|
|
|
+cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->min = min;
|
|
|
+ joint->max = max;
|
|
|
+
|
|
|
+ joint->jAcc = 0.0f;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpRotaryLimitJointInit(cpRotaryLimitJointAlloc(), a, b, min, max);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpSimpleMotor *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ joint->iSum = 1.0f/(a->i_inv + b->i_inv);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jMax = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= joint->jAcc*a->i_inv;
|
|
|
+ b->w += joint->jAcc*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpSimpleMotor *joint)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat wr = b->w - a->w + joint->rate;
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat j = -wr*joint->iSum;
|
|
|
+ cpFloat jOld = joint->jAcc;
|
|
|
+ joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);
|
|
|
+ j = joint->jAcc - jOld;
|
|
|
+
|
|
|
+
|
|
|
+ a->w -= j*a->i_inv;
|
|
|
+ b->w += j*b->i_inv;
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpSimpleMotor *joint)
|
|
|
+{
|
|
|
+ return cpfabs(joint->jAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpSimpleMotor)
|
|
|
+
|
|
|
+cpSimpleMotor *
|
|
|
+cpSimpleMotorAlloc(void)
|
|
|
+{
|
|
|
+ return (cpSimpleMotor *)cpmalloc(sizeof(cpSimpleMotor));
|
|
|
+}
|
|
|
+
|
|
|
+cpSimpleMotor *
|
|
|
+cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->rate = rate;
|
|
|
+
|
|
|
+ joint->jAcc = 0.0f;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpSimpleMotorInit(cpSimpleMotorAlloc(), a, b, rate);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+preStep(cpSlideJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
|
+{
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ joint->r1 = cpvrotate(joint->anchr1, a->rot);
|
|
|
+ joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
|
|
+
|
|
|
+ cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
|
|
+ cpFloat dist = cpvlength(delta);
|
|
|
+ cpFloat pdist = 0.0f;
|
|
|
+ if(dist > joint->max) {
|
|
|
+ pdist = dist - joint->max;
|
|
|
+ } else if(dist < joint->min) {
|
|
|
+ pdist = joint->min - dist;
|
|
|
+ dist = -dist;
|
|
|
+ }
|
|
|
+ joint->n = cpvmult(delta, 1.0f/(dist ? dist : (cpFloat)INFINITY));
|
|
|
+
|
|
|
+
|
|
|
+ joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat maxBias = joint->constraint.maxBias;
|
|
|
+ joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);
|
|
|
+
|
|
|
+
|
|
|
+ joint->jnMax = J_MAX(joint, dt);
|
|
|
+
|
|
|
+
|
|
|
+ if(!joint->bias)
|
|
|
+
|
|
|
+ joint->jnAcc = 0.0f;
|
|
|
+
|
|
|
+ cpVect j = cpvmult(joint->n, joint->jnAcc);
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, j);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+applyImpulse(cpSlideJoint *joint)
|
|
|
+{
|
|
|
+ if(!joint->bias) return;
|
|
|
+
|
|
|
+ cpBody *a = joint->constraint.a;
|
|
|
+ cpBody *b = joint->constraint.b;
|
|
|
+
|
|
|
+ cpVect n = joint->n;
|
|
|
+ cpVect r1 = joint->r1;
|
|
|
+ cpVect r2 = joint->r2;
|
|
|
+
|
|
|
+
|
|
|
+ cpVect vr = relative_velocity(a, b, r1, r2);
|
|
|
+ cpFloat vrn = cpvdot(vr, n);
|
|
|
+
|
|
|
+
|
|
|
+ cpFloat jn = (joint->bias - vrn)*joint->nMass;
|
|
|
+ cpFloat jnOld = joint->jnAcc;
|
|
|
+ joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, 0.0f);
|
|
|
+ jn = joint->jnAcc - jnOld;
|
|
|
+
|
|
|
+
|
|
|
+ apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));
|
|
|
+}
|
|
|
+
|
|
|
+static cpFloat
|
|
|
+getImpulse(cpConstraint *joint)
|
|
|
+{
|
|
|
+ return cpfabs(((cpSlideJoint *)joint)->jnAcc);
|
|
|
+}
|
|
|
+
|
|
|
+static const cpConstraintClass klass = {
|
|
|
+ (cpConstraintPreStepFunction)preStep,
|
|
|
+ (cpConstraintApplyImpulseFunction)applyImpulse,
|
|
|
+ (cpConstraintGetImpulseFunction)getImpulse,
|
|
|
+};
|
|
|
+CP_DefineClassGetter(cpSlideJoint)
|
|
|
+
|
|
|
+cpSlideJoint *
|
|
|
+cpSlideJointAlloc(void)
|
|
|
+{
|
|
|
+ return (cpSlideJoint *)cpmalloc(sizeof(cpSlideJoint));
|
|
|
+}
|
|
|
+
|
|
|
+cpSlideJoint *
|
|
|
+cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
|
|
|
+{
|
|
|
+ cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
|
|
+
|
|
|
+ joint->anchr1 = anchr1;
|
|
|
+ joint->anchr2 = anchr2;
|
|
|
+ joint->min = min;
|
|
|
+ joint->max = max;
|
|
|
+
|
|
|
+ joint->jnAcc = 0.0f;
|
|
|
+
|
|
|
+ return joint;
|
|
|
+}
|
|
|
+
|
|
|
+cpConstraint *
|
|
|
+cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
|
|
|
+{
|
|
|
+ return (cpConstraint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+*/
|