Cocos2d-JSでchipmunk使う備忘録

#はじめに
久しぶりにCocos2d-JS + chipmunkを使ったプロトタイプを作ろうとした時に、
いろいろ忘れてたので、自分用の備忘として残しておきます。

#chipmunkとは
物理演算をシュミレートするための2D物理演算のエンジン。
モンストや蹴り姫みたいなゲームが作れますというと一番伝わる気がします(笑)。

#Chipmunk vs Box2D
よく話題に出るのがこの２つの物理エンジンです。
細かいことはさておき、Chipmunkの方が先にCocos2dに組み込まれたっぽい記述がありましたが、
Cocos2dの3.0以上であれば、どちらもコアライブラリに機能として組み込まれているので、どちらを使っても良さそうです。今回はchipmunk使います。

#オブジェクトの作り方
1つのオブジェクトに対して、こんな流れになります。
1.sprite作る->2.body作る->3.Shape作る

1のspriteは通常のspriteと同じで、絵などを貼り付けたりなど描画する部分について。
2のbodyは位置や、動的/静的などを指定できたり、貼り付けるspriteを指定するなど。
3.のshapeはもっと細かな、形や密度、摩擦係数、反発係数などを指定し、
1~3を合体することで、1つの物理演算ルールに則ったオブジェクトを作成できます^^

#shapeのいろいろ
自作ゲームの中ではbox型地のshapeしか作ったことがなかったのですが、
いろいろ用意されているようです。

```js
cp.CircleShape(Body, 半径, オフセット)
cp.SegmentShape(Body, 始点, 終点, 線の太さ)
cp.PolyShape(Body, ポリゴンの頂点の配列, オフセット)
cp.BoxShape(Body, 幅, 高さ)
```


#実際の書き方

何はともあれ、project.jsonで読み込んでおきます。

```js
    "modules" : ["cocos2d","chipmunk"],
```

物理演算を行うspaceをinitの中で作成します。

```js
    initSpace: function() { 
        //物理演算する空間を作る
        this.space = new cp.Space();
 
        //重力がある場合はgravityを設定する
        //this.space.gravity = cp.v(0, -980);

        //shapeを可視化する（デバッグ用）
        this.addChild(new cc.PhysicsDebugNode(this.space));
 
        this.scheduleUpdate();
    },
```

次にupdateでは下記のように指定します。

```js
    update: function(dt) {
        // 物理エンジンの更新
        this.space.step(dt);
    },
```


いよいよオブジェクトの作成はこのような感じ。先に説明した通りに、1.sprite作る->2.body作る->3.Shape作るの順番で作っていきます。


```js

    addTank:function(posX,posY){
        // 物理スプライト
        this.tankSprite = new cc.PhysicsSprite("res/tank.png");  
        // 質量、慣性モーメントを設定
        this.weight = 100;
        this.tankBody = new cp.Body(this.weight, cp.momentForBox(this.weight, this.tankSprite.getContentSize().width, this.tankSprite.getContentSize().height));
        this.space.addBody(this.tankBody);
        // 形状、摩擦係数、反発係数を設定
        this.tankShape = new cp.BoxShape(this.tankBody, this.tankSprite.getContentSize().width, this.tankSprite.getContentSize().height);
        this.tankShape.setFriction(1);//摩擦係数
        this.tankShape.setElasticity(0.5); //弾性係数を設定
        this.space.addShape(this.tankShape);
        this.tankSprite.setBody(this.tankBody);
        this.tankSprite.setPosition(posX, posY);
        this.addChild(this.tankSprite);
    },
```

このまま実行すると、重力の設定などによっては画面外に飛び出しちゃうので、
とりあえず床などを作っておきます。

```js

createFloor: function() {
        // 床を静的剛体として作る
        var floorThickness = 10;

        var bottomBar = new cp.SegmentShape(this.space.staticBody, cp.v(0, 50), cp.v(640,50), floorThickness);
        bottomBar.setFriction(1); //摩擦係数
        bottomBar.setElasticity(0.3); //弾性
        this.space.addShape(bottomBar);

        var topBar = new cp.SegmentShape(this.space.staticBody, cp.v(0,1100), cp.v(640,1100), floorThickness);
        topBar.setFriction(1);
        topBar.setElasticity(0.3);
        this.space.addShape(topBar);

        var leftBar = new cp.SegmentShape(this.space.staticBody, cp.v(0,1100), cp.v(0,50), floorThickness);
        leftBar.setFriction(1);
        leftBar.setElasticity(0.3);
        this.space.addShape(leftBar);

        var rightBar = new cp.SegmentShape(this.space.staticBody, cp.v(640,1100), cp.v(640,50), floorThickness);
        rightBar.setFriction(1);
        rightBar.setElasticity(0.3);
        this.space.addShape(rightBar);
    },
```

初速を与えたい場合..

作ったオブジェクトに対して、初速を与えたい場合は(例えば、ピンボールの玉のような感じ)下記のようにして初速を与えることができます。

```js
        this.bulletBody.applyImpulse(cp.v(this.weight * 150, 0), cp.v(0, 0)); // 右向き
        this.bulletBody.applyImpulse(cp.v(0, this.weight * 1500), cp.v(0, 0)); // 上向き
```


#おしまい