前回のエントリの続き。詳しくは前回のエントリ見てね、っと。

今回はGameLayerクラスの自機ショットと敵(ただの岩)を作ってるところを見てみた。chipmunkの衝突判定もここら辺読めばわかりそう。

先に書いておくと、一つの物体作るのに三つの要素が必要になるみたい。Sprite、cpBody、cpShapeの三つ。

// 岩生成
-(void) makeSpaceRockX: (float) x y:(float)y
{
  // スプライト生成 
  Sprite *rock = [[Sprite spriteWithFile:@"rock.png"] retain];
  // 初期座標設定
  rock.position = cpv(x,y);
  // GameLayerにセット(画面に表示)
  [self addChild: rock];

  // 当たり判定用の領域作成
  // 後に作るcpBodyの中心からの相対座標を指定
  // ここでスプライトより小さく設定すれば
  // シューティングゲーのような実体より小さい当たり判定が作れそう
  cpVect verts[] = {
    cpv(-54,-43),
    cpv(-54, 43),
    cpv(54, 43),
    cpv(54,-43),
  };

  //cpBody生成
  // 第一引数は質量、第二引数は慣性モーメントらしいよ
  cpBody *rockBody = cpBodyNew(200.0f, INFINITY);
  // 座標設定
  rockBody->p = cpv(x, y);
  // 速度設定、動かないから0
  rockBody->v = cpv(0, 0);

  // 物理空間にセット
  cpSpaceAddBody(space, rockBody);

  //cpShape生成
  // 第二引数は当たり判定用配列の要素数を入れておけばいいっぽい?
  // 第四引数は重心の位置らしいよ?cpvzeroってのは中心ってことかね
  cpShape * rockShape = cpPolyShapeNew(rockBody, 4, verts, cpvzero);
  // eは弾性らしい。0〜1.0で、0だと無反射
  // uは摩擦係数。0だと摩擦無し
  rockShape->e = 0.9f; rockShape->u = 0.9f;
  // スプライトもここで登録。cpShapeにcpBodyとSprite全てが関連付けられた状態
  rockShape->data = rock;
  // 衝突タイプ。あとで説明
  rockShape->collision_type = 0; //New!
  // 物理空間にセット
  cpSpaceAddShape(space, rockShape);

  // 衝突したときの挙動を設定。衝突タイプと合わせてあとで説明
  cpSpaceAddCollisionPairFunc(space, 0, 1, &bulletCollision, self); //Also new!
} 



// 自機ショットの生成。
// 唯一気をつけて見ないといけない点は、衝突タイプが1であるところ
-(cpBody *) makeBulletX: (float) x y:(float) y 
{
  Sprite *laser = [[Sprite spriteWithFile:@"laser.png"] retain];
  [self addChild: laser];

  cpVect verts[] = {
    cpv(-7,-10),
    cpv(-7, 10),
    cpv(7, 10),
    cpv(7,-10),
  };

  cpBody *laserBod = cpBodyNew(100.0f, INFINITY);
  laserBod->p = cpv(x, y);
  laserBod->v = cpv(0, 0);

  cpSpaceAddBody(space, laserBod);

  cpShape * laserShape = cpPolyShapeNew(laserBod, 4, verts, cpvzero);
  laserShape->e = 0.9f; laserShape->u = 0.9f;
  laserShape->data = laser;
  laserShape->collision_type = 1; //this is new!
  cpSpaceAddShape(space, laserShape);

  return laserBod;	
}

衝突タイプってなんぞやーって感じだけど、cpSpaceAddCollisionPairFuncの引数と密接に関係している。

cpSpaceAddCollisionPairFunc(space, 0←「衝突タイプ0」, 1←「衝突タイプ1」, &bulletCollision, self);

つまり上の場合、衝突タイプ0の物体と衝突タイプ1の物体が衝突したらbulletCollisionが呼ばれますよ、ってこと。

試しに岩かショットの衝突タイプのうちどちらかを2にしてビルドすると、ショットを撃っても岩は破壊されずに反射しちゃう。イベントが呼ばれずに普通に物理演算してしまうってこと。

そのあとで、cpSpaceAddCollisionPairFuncのほうの衝突タイプを2に変更すれば元の挙動に戻ることがわかる。これって定数とかにしたほうが良さそうかも。

chipmunkのcpBody、cpShapeだけど、構造体なので中身見ないとよくわからない。以下のようになってるらしいよ?

英語読めるなら原典当たったほうが早いwChipmunk Game Dynamics

typedef struct cpBody{
    cpFloat m; //質量
    cpFloat m_inv; //質量の逆。なにそれ斥力?
    cpFloat i; //慣性モーメント
    cpFloat  i_inv; //慣性モーメントの逆らしい?

    cpVect p; //座標
    cpVect v; //速度
    cpVect f; //force respectively だそうです
    cpFloat a; //角度(radians)
    cpFloat w; //角速度(rad/sec)
    cpFloat t; //torque respectively だそうです
    cpVect rot; //ユニット長ベクトルとしてのボディーの回転 だそうです
} cpBody
typedef struct cpShape{
    cpBB bb; // The bounding box of the shape. Only guaranteed to be valid after cpShapeCacheBB() is called.

    unsigned long collision_type; //衝突タイプ
    unsigned long group; // わからんw Shapes in the same non-zero group do not generate collisions. Useful when creating an object out of many shapes that you don’t want to self collide. Defaults to 0
    unsigned long layers; // わからんw Shapes only collide if they are in the same bit-planes. i.e. (a->layers & b->layers) != 0 By default, a shape occupies all 32 bit-planes.

    void *data; //A user definable field.とくにスプライト設定用というわけでもないらしい

    cpBody *body; //cpBody
    cpFloat e; //弾性
    cpFloat u; //摩擦係数
    cpVect surface_v; //オブジェクトの表面速度。ベルトコンベアーのような物体を作るときに使用
} cpShape;

なんとなくchipmunkを理解してきたかもってことで今回は終わり。