JavaScript
HTML5
Box2dWeb
ゲーム制作
phina.js
phina.jsDay 14

phina.jsからBox2dを使う(基礎編)

この記事はphina.js Advent Calendar 2017 14日目の記事です。
← 13日目:phina.js のイベント一覧  15日目:phina.jsのクラス構文について(予定) →

Box2dとは

Box2dはゲーム用の2d物理エンジンで、元々はC++で作られたものですが、Box2dWebという名前でjavascriptにも移植されています。Box2d自体は有名なライブラリであり、Web上での解説記事も多いので、ここでの詳細な説明は割愛します。Angry Birdに使われているとか良く触れられていますね。

Box2dWebとphina.jsの連携について

有名なBox2dではありますが、いざ使おうとすると、結構面倒な前処理を自前で書く必要があります。
phina.jsには、このような処理を書かずにBox2dWebをより簡単に使うことができるクラスが用意されています。

クラス名 役割
phina.box2d.Box2dLayer 主にBox2dを使用するための前処理を行います。
phina.box2d.Box2dBody 物体の定義やBox2dとphina.jsとの間の座標及びスケールの調整などを行います。

ライブラリの読み込み

Box2dWebをhtmlで読み込みます。本家のものだと何故か上手く読み込まれなかったので、今回は@phiさんがforkしてbugfixしたバージョンを使用します。

    <script src="https://rawgit.com/phi-jp/box2dweb/master/Box2D.js"></script>
    <script src="http://cdn.rawgit.com/phi-jp/phina.js/v0.2.1/build/phina.js"></script>

レイヤーの作成

最初にBox2d表示用のレイヤーを作ってSceneに追加します。

// グローバルに展開
phina.globalize();
// 定数
var SCREEN_WIDTH = 640;
var SCREEN_HEIGHT = 960;
/*
 * メインシーン
 */
phina.define("MainScene", {
  // 継承
  superClass: 'DisplayScene',
  // 初期化
  init: function() {
    // 親クラス初期化
    this.superInit();
    // 背景色
    this.backgroundColor = 'black';
    // Box2d用レイヤー作成
    var layer = Box2dLayer({
      width: SCREEN_WIDTH,
      height: SCREEN_HEIGHT,
    }).addChildTo(this);

レイヤーは、画面サイズと同じサイズにしないと位置がずれるので注意しましょう。

物体を追加する

落下するボール

簡単な例として、落下するボールを追加してみます。

falling_ball.gif

[runstantで動作確認]

    // Box2d用レイヤー作成
    var layer = Box2dLayer({
      width: SCREEN_WIDTH,
      height: SCREEN_HEIGHT,
    }).addChildTo(this);
    // ボール
    var ball = CircleShape().addChildTo(this);
    ball.setPosition(this.gridX.center(), this.gridY.center());
    // Box2dのデバッグ表示が見えるようにする
    ball.alpha = 0.5;
    // Box2dオブジェクトを作成してballにアタッチ
    layer.createBody({
      type: 'dynamic', 
      shape: 'circle',
    }).attachTo(ball);
  • 先にphina.jsのオブジェクトであるCircleShapeを作成して、Sceneに追加しています。
  • その後、Box2dLayerのメソッドであるcreateBodyBox2dオブジェクトを作成して、CircleShapeにアタッチしています。
  • createBodyのパラメータのうち、typeには重力などが適用されるdynamicを指定し、形状を表すshapeにはcircleを指定しています。
  • アタッチすると、以後Box2d側の動きとphina.js側の動きが同期するようになります。

固定の床

このままではボールが落ちるだけなので、障害物となる床を配置します。

falling_bounce_ball.gif

[runstantで動作確認]

    // 床
    var floor = RectangleShape({
      width: SCREEN_WIDTH,
      height: 32,
    }).addChildTo(this);
    floor.setPosition(this.gridX.center(), this.gridY.span(15));
    // Box2dのデバッグ表示が見えるようにする
    ball.alpha = 0.5;
    // Box2dオブジェクトを作成してfloorにアタッチ
    layer.createBody({
      type: 'static', 
      shape: 'box',
    }).attachTo(floor);
  • 床はphina.js側ではRectangleShapeで表示します。
  • 床は固定で動かないのでtypestaticにします。
  • 形状を表すshapeboxにします。

これで、ボールが床に当たり跳ねるようになりました。

床に角度をつける

ここまでだと余りBox2dの恩恵に預かっていないので、より物理的な動きを確認するために床を傾けてみます。

falling_rolling_ball.gif

[runstantで動作確認]

    // Box2dオブジェクトを作成してfloorにアタッチ
    layer.createBody({
      type: 'static', 
      shape: 'box',
    }).attachTo(floor).body.SetAngle(Math.degToRad(10));
  • phina.jsに慣れているとshaperotationを設定したくなりますが、phina.js側はBox2dの動きを追従しているだけなので、Box2dのメソッドを使う必要があります。
  • Box2dBodyクラスのプロパティbodyBox2dのオブジェクトを参照できるので、SetAngleメソッドで角度(radian)を設定しています。

これで、ボールが床に落ちて転がっていきます。

おわりに

以上がphina.jsからBox2dを使う簡単な方法です。まだ紹介出来ていない部分も多くあると思いますし、私自身もまだまだ勉強中てす。

  • Shapeではなくスプライトを使う
  • Box2dのデバック描画をしないようにする

などが次にトライできるテーマでしょう。
結構簡単に連携できることがお分かり頂けたと思いますので、皆さんの方でも色々と試して遊んでみて下さい。