すくまりのメモ帳すくまりのメモ帳
← 記事一覧に戻る

【EgretEngine】p2.js 物理エンジンを使用した自然落下

2018-12-28
【EgretEngine】p2.js 物理エンジンを使用した自然落下

はじめに

この記事では p2.js 物理エンジンを使用して、

EgretEngineのオブジェクトに物理現象を加えていきます。

フィア: 結構むずかしかったね…

カレン: Unityと比べると手順も多いから頑張ろうね

準備

p2.js 物理エンジンのダウンロード

1、egret-game-libraryのダウンロード

GitHubより、「egret-game-library」をダウンロード。

https://github.com/egret-labs/egret-game-library

「egret-game-library」を解凍して、egret-game-library-master/physics/libsrc/binを開きます。

その中の「physics」フォルダを、プロジェクトフォルダがある場所にコピーしてください。

場所は、「Egret Launcher」を起動して、Open project locationを押せば分かります。

2、p2.js物理エンジンの適用

プロジェクトを開き、「egretProperties.json」を開いてください。

次に、

    {
      "name": "physics",
      "path": "../physics"
    },

を追加してください。

{
  "engineVersion": "5.2.13",
  "compilerVersion": "5.2.13",
  "template": {},
  "target": {
    "current": "web"
  },
  "modules": [
    {
      "name": "egret"
    },
    {
      "name": "eui"
    },
    {
      "name": "assetsmanager"
    },
    {
      "name": "tween"
    },
    {
      "name": "promise"
    },
    {
      "name": "physics",
      "path": "../physics"
    },
    {
      "name": "game"
    }
  ]
}

ここで注意点です。

このjsonファイル内では、ダブルスラッシュでコメントを付けるとエラーになります。

できるだけ、余計なものはつけないようにしましょう。

「../」は、jsonファイルの1つ上のフォルダへ行くという意味です。

また、

    {
      "name": "game"
    }

をついでに付けておきましょう。

これは「MainContext」というコードを使用するときに使用します。

MainContextは、

egret.MainContext.instance.stage.stageHeight;

のように使用し、ステージ(画面)の高さや幅を取得するときに使います。

ゲームをデバッグで実行すると、modulesフォルダ内にphysicsが生成されます。これで完了です。

p2.js 物理エンジンを使用した自然落下

Main.ts

class Main extends eui.UILayer {
 
        public constructor() {
        super();
        
        this.once(egret.Event.ADDED_TO_STAGE, this.addToStage, this);
    }
 
 
    private addToStage(event:egret.Event) {
 
        //物理エンジンを使うようのフィールドを作成
        const world = new p2.World();
        world.sleepMode = p2.World.BODY_SLEEPING;
        world.gravity = [0, 9.8 * 50];
 
 
        //物理挙動をもつコライダーの生成
        const body : p2.Body = new p2.Body({mass:1, position:[200,300]});
        const bodyShape = new p2.Circle({ radius: 100 });
        body.addShape(bodyShape);
        world.addBody(body);
 
        //ループ処理
        egret.Ticker.getInstance().register(loopMethod,this);
 
        function loopMethod(dt:number) {
            world.step(1/60, dt/1000, 10);
            drawBall();
        }
 
 
        //図形の表示用オブジェクトのインスタンス化
        const shape:egret.Shape = new egret.Shape();
        this.addChild(shape);
 
        //ボールの描画
        function drawBall(){
            //ステージに残っている図形を一度消す
            shape.graphics.clear();
 
            shape.graphics.beginFill(0xff0000);
            shape.graphics.drawCircle(body.position[0], body.position[1], 100);
            shape.graphics.endFill();
 
        }
 
        
    }
 
}

物理現象をステージに付与

const world = new p2.World();
world.sleepMode = p2.World.BODY_SLEEPING;
world.gravity = [0, 9.8 * 50];

「world.sleepMode = p2.World.BODY_SLEEPING; 」は、一定時間が経過したオブジェクトの物理エンジンをスリープ状態にし、パフォーマンスを向上させます。

「world.gravity = [0, 9.8 * 50];」でステージに重力を付与します。

ここで注意点ですが、p2.js と EgretEngineは長さの単位が異なるうえ、座標系も違います。

なので、座標を補正してあげる必要があるため、50を掛けています。

物理世界の座標系と長さの計算

P2物理引擎——物理小球案例

物理挙動を持つコライダーの生成

const body : p2.Body = new p2.Body({mass:1, position:[200,300]});
const bodyShape = new p2.Circle({ radius: 100 });
body.addShape(bodyShape);
world.addBody(body);

コライダーは接触判定をおこなったり、壁にめり込まないように計算してくれるワイヤーフレームです。

詳しくは、こちらのコライダーの記事もご覧ください。

当たり判定を付与できるコライダーの種類まとめ

「const body : p2.Body = new p2.Body({mass:1, position:[200,300]});」でコライダーを生成します。

 var body = new Body({
      mass: 1,
      position: [0, 0],
      angle: 0,
      velocity: [0, 0],
      angularVelocity: 0
});

のように、{ } の中でposition や angle 等を設定できます。

BodyのAPIについては以下の公式サイトをご覧ください。

p2.js Body Class API

「const bodyShape = new p2.Circle({ radius: 100 });」でコライダーを円形に切り取る準備をします。

最後に「body.addShape(bodyShape);」でコライダーを円形に切り取り、「world.addBody(body);」で画面に追加します。

ループ処理「egret.Ticker.getInstance()」

//ループ処理
egret.Ticker.getInstance().register(loopMethod,this);
 
function loopMethod(dt:number) {
    world.step(1/60, dt/1000, 10);
    drawBall();
}
 

ループ処理を行うには「egret.Ticker.getInstance().register( 関数 ,this);」を使用します。

「world.step(秒,  関数が最後に呼び出されてからの経過時間,  関数の呼び出しごとにとる固定ステップの最大数);」です。

このメソッドを使って円の描画をしていきます。

コライダーだけでは無色透明なので、図形の描画は必要です。

図形の描画

//図形の表示用オブジェクトのインスタンス化
const shape:egret.Shape = new egret.Shape();
this.addChild(shape);
 
//ボールの描画
function drawBall(){
    //ステージに残っている図形を一度消す
    shape.graphics.clear();
 
    shape.graphics.beginFill(0xff0000);
    shape.graphics.drawCircle(body.position[0], body.position[1], 100);
    shape.graphics.endFill();
 
}

上記コードで円の描画をおこなっております。円の描画方法は以下の記事も参照してください。

【eui.UILayer】図形の描画方法「drawCircle」「drawRect」「lineTo」

「shape.graphics.clear();」で現在ステージに描画してあるオブジェクトを消去します。

これがないと、以下のように線状になります。

参考URL

物理世界の座標系と長さの計算

P2物理引擎——物理小球案例

p2.js Body Class API

EgretEngineで超簡単なゲームを作ってみよう(2) 物理エンジン エクステンションの導入

EgretEngineで超簡単なゲームを作ってみよう(3) タップでの操作の実装

次回の記事

/posts/egretengine-physics-many-object/

HTML5 Egret Engine入門講座へ戻る