さえめろ の めも🐰

さえめろの備忘録です。twitter : @sae_mero_

Cocos Creatorで物理演算を使ってみる

Cocos Creatorで物理演算を使ってみたよ〜というメモ。
よく物理演算を使った落ち物ゲーなどでみるような動きをCocos Creatorでもやってみます。


■環境
・Cocos Creator v1.3.2
Mac OS X yosemite 10.10.5
・使用言語:JavaScript


■手順
<1> プロジェクトファイルを作成する。
Cocos Creatorを起動し、Dashbaord -> New Project -> Empty Project を選択し、適当な名前をつけて新規プロジェクトを作成。 
f:id:saemero:20170603081058p:plain
CanvasのPropertiesから、カンバスサイズを1000×500くらいに変更しておきます。

<2> 画像を追加する。
物理演算を適用したい画像(パズルなど)を、ExplorerやFinderからAsettsへドラッグ&ドロップします。
f:id:saemero:20170603095212p:plain
↑ここ
今回は自作した70×70pxのにこちゃんを使います。


<3> にこちゃんPrefabを作成する。
AssetsからNode Treeへにこちゃんをドラッグ&ドロップし、追加されたにこちゃんをもう一度Asettsへ戻します。
f:id:saemero:20170603100636p:plainf:id:saemero:20170603100546p:plain
上の四角いアイコンが付いているのがPrefab化されたにこちゃん。

Node Treeに追加されたにこちゃんはもう使わないので、削除しましょう。
これで複数の同じSpriteを動的に生成できるようになります。

<4> スクリプトを記述する。
Assets -> Create -> JavaScript から新しいjsファイルを作成します。
名前はnikochanScriptとかにしておきましょう。
まずはpropertiesの中身の設定をします。

properties: {
    nikochan: {
        default: null,
        type: cc.Prefab
    },
},

ここににこちゃんPrefabを紐付けることで、Script内で使えるようになります。

次に、物理演算部分の記述です。
Cocos Creatorで使用できる言語はCoffeeScriptJavaScriptの二択です。
Cocos2d-xには「Box2D」と「Chipmunk」という二つの物理エンジンがありますが、JavaScriptでは「Chipmunk」しか使用できないので、今回はそちらを使います。

まずはonLoad内の記述から。

onLoad: function () {
        
    // 初期化
    this.shapeArray = [];
        
    // プレハブからスプライトを生成する関数を1秒ごとに呼び出す
    this.schedule(this.generateNikochan, 1);
        
    // 空間の作成
    this.world = new cp.Space();
    
    // 重力の設定
    this.world.gravity = cp.v(0, -100);

    // 床の設定
    // XYともに長さを無限に設定
    var body = new cp.Body(Infinity, Infinity);
    // Y方向-200の位置にセット
    body.setPos(cp.v(0, -200));
    
    // 床の物理特性
    var shape = new cp.BoxShape(body, 1000, 20);
    shape.setFriction(1);
    shape.setElasticity(0);
    this.world.addShape(shape);
},

にこちゃんを落とす空間と、そこに存在する床を作ることができました。
ここで使われているChipmunkのメソッドは以下の通りです。

メソッド 機能
cp.Space() 物理演算空間を作成
space.gravity = cp.v(x, y) spaceに働く重力の設定
cp.BoxShape(body,num,num) 四角形のshapeを作成
shape.setFriction(num) shapeに摩擦係数を設定
shape.setElasticity(num) shapeに弾性係数を設定
space.addShape(shape) spaceにshapeを追加


続いてupdate関数の中身です。

update: function (dt) {
    // 物理シミュレーションを毎フレームごとにする
    this.world.step(dt);

    // スプライトと物体の同期
    for (var i = this.shapeArray.length - 1; i >= 0; i--) {
        // 画像の位置と角度を変更する
        this.shapeArray[i].image.x = this.shapeArray[i].body.p.x;
        this.shapeArray[i].image.y = this.shapeArray[i].body.p.y;
        var angle = Math.atan2(-this.shapeArray[i].body.rot.y,this.shapeArray[i].body.rot.x);
        this.shapeArray[i].image.rotation = angle * 57.2957795;
    }
},

物理演算を毎フレームごとに行い、物体の位置関係を更新します。
メソッドは以下。

メソッド 機能
space.step(num) 物理空間の時間をnumの値だけ進める

これをdtを引数としてupdate関数内で記述すると、フレームごとに時間を進めてくれます。


最後に、にこちゃんを生成する関数を書きます。

generateNikochan: function (dt) {

        // にこちゃん出現位置を x=0~500までのランダム, y=200で設定
        var x = cc.random0To1() * 1000 - 500;
        var y = 200;
        
        // 物体の種類設定
        var body = new cp.Body(1, cp.momentForBox(1, 70, 70));
        body.setPos(cp.v(x, y));

        // 画像の用意
        var nikochan = cc.instantiate(this.nikochan);
        nikochan.setPosition(cc.p(x, y));
        this.node.addChild(nikochan);

        // 物理空間への配置
        this.world.addBody(body);

        // 物理特性
        var shape = new cp.CircleShape(body, 35, cp.vzero);
        shape.setFriction(1);
        shape.setElasticity(0);
        shape.image = nikochan;
        this.world.addShape(shape);
        this.shapeArray.push(shape);
        
    }

これでPrefabから生成されたにこちゃんに物理特性を付与できました。

メソッド 機能
cp.CircleShape(body,半径,オフセット) 円状のshapeを作成
shape.image = image shapeにスプライトを設定

スクリプトの記述は以上で完了です。

<5> いろいろ紐付ける。
まず、今記述したスクリプトCanvasコンポーネントします。
CanvasのPropertiesのAdd Componentをクリックし、Add Custom Component -> 先ほど作成したnikochanScriptを選択します。
f:id:saemero:20170603113825p:plain

これで紐付けができました。
先ほど作成したPrefabを[Nikochan]にドラッグ&ドロップすれば、Script内のnikochanとにこちゃんPrefabが紐付きます。
f:id:saemero:20170603114451p:plain

最後に、Assets -> Create -> Sceneでシーンを作成し、保存します。

以上で完了!

ソース全文はこちら(github