一,基本概念
space: 發生物理模擬的空間,可容納body, shape,joint
body:剛體,可被賦予shape。剛體具有質量,轉動慣量,位置,線性速度,加速度,角度,角速度,角加速度等屬性。剛體之間可通過joint連線
shape:決定剛體的碰撞外形。一個剛體上可覆蓋上多個shape,同屬於一個剛體的shape不會互相發生碰撞。shape同樣需要加到space中。有圓,線段,凸多邊形這三種shape類型。
joint: 用於連線剛體。有4種類型:
pin joint: 相當於一根棍子(質量忽略)加兩個大頭針(錨點),兩個剛體如果用pin joint連線,他們之間的距離不會改變,他們各自可繞錨點轉動(如果有力矩的話)
slide joint: 相當於把pin joint的棍子換成了滑槽。這個滑槽有最大和最小長度。
pivot joint: 即一個旋轉軸。兩個剛體都繞這個軸旋轉
groove joint:相當於可滑動的pivot joint。將剛體2的旋轉軸掛到處於剛體1的一段滑槽上。
坐標系:demo里都使用的是2d笛卡爾坐標系。猜想對於2d遊戲如果使用螢幕坐標系應該也可以(只是y反了)。或者在繪製2d sprite的時候自己轉換一下坐標吧,應該更清楚些。
單位:引擎沒有指定,最好使用國際單位制如kg,m,s,保持單位一致很重要
二,基本用法
0)初始化chipmunk引擎,調用cpInitChipmunk()
1)構建sapce,使用cpSpaceNew()
2) 構建一個static body,作為關卡的物理環境。這個body不需要加入到space中,否則會受重力作用。但這個body的shape需要加入到space中,用作碰撞檢測。
staticBody = cpBodyNew(INFINITY, INFINITY); //生成static body,一般一個場景有一個夠了
shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f);//在static body上生成一個線段shape,也可以使用圓和多邊形
cpSpaceAddStaticShape(space, shape);//將這個shape加入到space中
3)生成剛體body,和static body類似,只是使用cpBodyNew,另外需要使用cpSpaceAddBody(space, body);將body加入到space中。例子:
cpVect verts[] = {
cpv(-15,-7),
cpv(-15, 7),
cpv( 15, 7),
cpv( 15,-7),
};
cpBody *body = cpBodyNew(1.0, cpMomentForPoly(1.0, num, verts, cpv(0,0)));//第二個參數是轉動慣量,一般用這個函式計算就可以了
body->p = cpv(x, y);//可設定body的位置
cpSpaceAddBody(space, body);//body要加入space中
cpShape *shape = cpPolyShapeNew(body, num, verts, cpv(0,0));
shape->e = 0.0; shape->u = 1.0;
cpSpaceAddShape(space, shape);//shape要加入space中
4) 加入joint:每個joint都是對於兩個body的。使用cpPivotJointNew之類的方法加入joint,然後還要使用cpSpaceAddJoint將joint加入到space中
5)進行物理模擬計算:
其 實只要調用cpSpaceStep(space, dt);就可以了。如果使用了外力,比如cpDampedSpring這樣的方法,就要先清除一下body上的力和力矩,使用 cpBodyResetForces,另外如果需要提高精度,可以將dt分為幾個step。例子:
void demo7_update(int ticks)
{
int steps = 3;
cpFloat dt = 1.0/60.0/(cpFloat)steps;
for(int i=0; i
cpBodyResetForces(chassis);
cpBodyResetForces(wheel1);
cpBodyResetForces(wheel2);
cpDampedSpring(chassis, wheel1, cpv(40, 15), cpvzero, 50.0f, 150.0f, 10.0f, dt);
cpDampedSpring(chassis, wheel2, cpv(-40, 15), cpvzero, 50.0f, 150.0f, 10.0f, dt);
cpSpaceStep(space, dt);
}
}
6)釋放對象
這樣就可以全部釋放:
cpSpaceFreeChildren(space); //釋放所有加入到space中的body, shape, joint
cpSpaceFree(space);
cpBodyFree(staticBody);//靜態body沒有加入space需要單獨釋放
三,碰撞回調
物理引擎本身會讓物體在碰撞後產生“正確”的反應。但是你還是可以讓碰撞時調用自己的方法,甚至取消掉碰撞。
使用:cpSpaceAddCollisionPairFunc(space, 1, 0, &collFunc, &some_value);
static int
collFunc(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data)
{
int *some_ptr = (int *)data;
// Do various things with the contact information.
// Make particle effects, estimate the impact damage from the relative velocities, etc.
// for(int i=0; i
// printf("Collision at %s. (%d - %d) %d\n", cpvstr(contacts[i].p), a->collision_type, b->collision_type, *some_ptr);
// Returning 0 will cause the collision to be discarded. This allows you to do conditional collisions.
return 1;
}
四,速度函式
body->velocity_func = apply_buoyancy;//設定了一個自定義的速度計算函式
這個函式給剛體加入了水面的浮力(demo6)。
// Apply an approximate bouyancy and drag force to an object.
static void
apply_buoyancy(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{
int numx = 20;
int numy = 4;
float stepx = (float)WIDTH/(float)numx;
float stepy = (float)HEIGHT/(float)numy;
cpBodyResetForces(body);//先清除力和力矩
for(int x=0; x
for(int y=0; y
cpVect p_sample = cpv((x + 0.5)*stepx - WIDTH/2, (y + 0.5)*stepy - HEIGHT/2);
cpVect p = cpBodyLocal2World(body, p_sample);
cpVect r = cpvsub(p, body->p);
if(p.y < 0){
cpVect v = cpvadd(body->v, cpvmult(cpvperp(r), body->w));
cpVect f_damp = cpvmult(v, -0.0003*cpvlength(v));
cpVect f = cpvadd(cpv(0, 2.0), f_damp);//計算浮力
cpBodyApplyForce(body, f, r);//將力作用上
}
}
}
cpBodyUpdateVelocity(body, gravity, damping, dt);//默認的應該只有這句吧,作用上重力和阻力。
}
五,其他
可以加上衝量:
cpBodyApplyImpulse
shape查詢:
typedefvoid(*cpSpacePointQueryFunc)(cpShape *shape,void*data)void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpLayers group, cpSpacePointQueryFunc func,void*data)cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpLayers group)