tmlib.jsとbox2dwebを組み合わせてみた

大分間が空いていますがゲーム開発再開しました。
GWを利用して
AWSのEC2環境下にnodejsのサーバを立てました。
ちなみにAmazonのドメインはわかりづらいので
ドメインはお名前.comで新規取得してRoute53で設定しています。
（AWSのほうは気が向いたら書くかもしれません・・・）

ゲームのほうは
tmlib.jsとtmlib.novel.jsとbox2dWebを使っていこうかと思います。
（とりあえず組み合わせに成功したので備忘録として残しておきます）



tmlib.jsはjavascriptのクライアントサイドの描画や音声系のライブラリです。
box2dWebのほうは2Dの物理エンジンです。
上記２つは説明はしょります。使い方は私の前に書いた記事を見てください

tmlib.novel.jsはノベルゲーム製作用のtmlibプラグインみたいです。
http://jsdo.it/phi/tgGy


<hr>

全ソースコードです。
個人的にtmlib.jsが0.4.0以降でシーン制御が大分変わっていて焦りました。
また、Box2dDebugDrawクラスを定義してBox2Dのデバッグ描画をできるようにしました。
別途game.novelスクリプトも必要なのでそれも載せておきます。

```index.html
<!DOCTYPE html>

<html>
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, user-scalable=no" />
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
        <title>ゲームタイトル</title>

<!--        <script src="tmlib.js"></script>-->
        <script src="tmlib_0.5.0.js"></script>
        <script src="tmlib.novel.js"></script>
        <script type="text/javascript" src="Box2dWeb-2.1.a.3.min.js"></script>
<script>

// box2dParam    
var b2Vec2 = Box2D.Common.Math.b2Vec2 // 2Dベクトル
 ,  b2BodyDef = Box2D.Dynamics.b2BodyDef // Body定義
 ,  b2Body = Box2D.Dynamics.b2Body // Body
 ,  b2FixtureDef = Box2D.Dynamics.b2FixtureDef // Fixture定義
 ,  b2Fixture = Box2D.Dynamics.b2Fixture // Fixture
 ,  b2World = Box2D.Dynamics.b2World // 物理世界
 ,  b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape // 衝突オブジェクトの形状（ポリゴン）
 ,  b2CircleShape = Box2D.Collision.Shapes.b2CircleShape  // 衝突オブジェクトの形状（円）
 ,  b2DebugDraw = Box2D.Dynamics.b2DebugDraw // デバッグ描画


 
/*
 * box2dDebugDraw
 */
tm.display = tm.display || {};

(function() {
    
    tm.display.Box2dDebugDraw = tm.createClass({
        superClass: tm.display.CanvasElement,
        
        /**
         * @constructor
         * @param box2dWorld box2dのworld
         */
        init: function(box2dWorld) {
            this.superInit();
            
            this.world = box2dWorld;
            
            // デバッグ描画の設定      
            this.debugDraw = new b2DebugDraw();
            this.debugDraw.SetSprite ( document.getElementById ("canvas").getContext ("2d"));
            this.debugDraw.SetDrawScale(30);     //描画スケール
            this.debugDraw.SetFillAlpha(0.3);    //半透明値
            this.debugDraw.SetLineThickness(1.0);//線の太さ
            this.debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
            this.world.SetDebugDraw(this.debugDraw);

        },
        // override
        draw: function(){
            this.world.DrawDebugData(); // デバック描画
        }
    });
        
})();
    

    
/**
 * スクリーンサイズ
 */

var SCREEN_WIDTH    = 640;              // スクリーン幅
var SCREEN_HEIGHT   = 960;              // スクリーン高さ
var SCREEN_CENTER_X = SCREEN_WIDTH/2;   // スクリーン幅の半分
var SCREEN_CENTER_Y = SCREEN_HEIGHT/2;  // スクリーン高さの半分

    
tm.define("MainScene", {
    superClass: "tm.game.ManagerScene",
 
    init: function(app) {
        
        this.score = 0;
        
        // 初期化時にどう遷移するか指定してあげる
        this.superInit({
            scenes: [
                {
                    className: "tm.game.LoadingScene",
                    label: "loading",
                    arguments: {
                        assets: {
                            "title":{
                                path:"title.jpg",
                                type:"jpg"
                            },
                            "result":{
                                path:"result.jpg",
                                type:"jpg"
                            },
                            "novel": {
                                path: "/game/game.novel",
                                type: "novel",
                            },
                            "bg": {
                                path: "/game/back.jpg",
                                type: "jpg",
                            },
                            "frame": {
                                path: "/game/border.png",
                                type: "png",
                            },
                            "player": {
                                path: "/game/tori.png",
                                type: "png",
                            },
                            "bgm": {
                                path: "/game/sound.mp3",
                                type: "mp3",
                            }
                        }, 
                        width: SCREEN_WIDTH,
                        height: SCREEN_HEIGHT,
                        bgColor:"lime",
                        autopop: true
                    }
                },
                {
                    className: "tm.game.TitleScene",
                    label: "title",
                    arguments: {
                        title :  "ゲームタイトル",
                        message: "",
                        bgColor: "black",
                        bgImage: "title",
                        width :  SCREEN_WIDTH,
                        height : SCREEN_HEIGHT,
                        fontColor: "white",
                        fontSize: 60,
                        autopop: true
                    }
                },  
                {
                    className: "TutorialScene",
                    arguments: {
                        app: app
                    },
                    label: "tutorial"
                },
                {
                    className: "GameScene",
                    arguments: {
                    },
                    label: "game"
                },
                {
                    className: "tm.game.ResultScene",
                    label: "result",
                    arguments: {
                        bgColor: "black",
                        bgImage: "result",
                        score: this.score,
                        message:  "ゲームクリア",
                        url:      "",
                        hashtags: ["tmlib.js"],
                        width:    SCREEN_WIDTH,
                        height:   SCREEN_HEIGHT,
                        fontColor: "white",
                        fontSize: 60
                    },
                    nextLabel: "title"
                },
            ]
        });
    },
});
    
    



/**
 * ゲーム起動処理
 */
tm.main(function() {
    // アプリケーション作成
    var app = tm.app.CanvasApp("#canvas");
    app.resize(SCREEN_WIDTH, SCREEN_HEIGHT); // 画面サイズに合わせる
    app.fitWindow(); // リサイズ対応
    
    // シーンの切り替え
    app.replaceScene(MainScene(app));

    // tmlibの実行
    app.run();
});




/**
 * TurtorialScene
 */
tm.define("TutorialScene", {
    superClass : "tm.app.Scene",

    init : function(param) {
        this.superInit();
        
        var app = param.app;

        var elm = tm.novel.Element("novel").addChildTo(this);
        elm.ontaskfinish = function() {
            // シーンの遷移
            app.popScene();
        };     

    },

    onpointingstart: function() {
        //this.app.popScene();
    }

});



/**
 * GameScene
 */
tm.define("GameScene", {
    superClass : "tm.app.Scene",

    init : function() {
        this.superInit();

        this.world = new b2World(new b2Vec2(0,10), true);

        // 動的衝突オブジェクト生成      
        var bodyDef = new b2BodyDef;
        bodyDef.type = b2Body.b2_dynamicBody;
        bodyDef.position.Set(4,8);
        bodyDef.userData = 'obj';
      
        // 材質と形状
        var fixDef = new b2FixtureDef;
        fixDef.density = 10.0;
        fixDef.friction = .9;
        fixDef.restitution = .2; 
        fixDef.shape = new b2CircleShape(1); // 円形状
        
        // 円
        var wheel = this.world.CreateBody(bodyDef);
        wheel.CreateFixture(fixDef);
      
        // 角速度（回転速度）指定
        wheel.SetAngularVelocity(Math.PI*2);
        // 位置と角度指定 
        wheel.SetPositionAndAngle(new b2Vec2(2,3),-20*(Math.PI/180));
 
        // 静的衝突オブジェクト
        var bodyDef = new b2BodyDef;
        bodyDef.type = b2Body.b2_staticBody;
        bodyDef.position.Set(10,12);
      
        // 材質と形状
        var fd = new b2FixtureDef;
        fd.shape = new b2PolygonShape;
        fd.shape.SetAsBox(10,1); // 箱型形状
        
        // 地面
        var holder = this.world.CreateBody(bodyDef);
        holder.CreateFixture(fd);
    
        // Box2Dデバッグ描画の設定      
        this.debugDraw = new tm.display.Box2dDebugDraw(this.world); 
        // 当たり判定なので最後に追加すること
        this.addChild(this.debugDraw);

        this.score = 0;
                
    },

    update: function (app) {
                       
        this.world.Step(1 / 60, 10, 10); // 物理世界を更新する
        this.world.ClearForces(); // 物理世界上の力をリセットする
        
    },
    
    onpointingstart: function() {
        this.app.popScene();
    }

});


           
</script>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
</html>
```

tmlib.novel.jsは吉里吉里ライクなスクリプトで
会話部分を作成するのに大変便利な代物です。
今回はシーン制御のため、サンプルを少し改修しました。

```game.novel

// 背景を表示
[new name=bg type=tm.display.Sprite arg=bg originX=0 originY=0 width=960 height=640]
// 枠を表示
[new name=frame layer=2 type=tm.display.Sprite arg=frame x=320 y=580 alpha=0.8]

// bgm を再生
[music_play name=bgm]

// フォントを指定
[font color=#222]
// フォント表示位置
[position x=120 y=540]

*start

// プレイヤーを表示
[new name=player type=tm.display.Sprite arg=player x=320 y=400 scaleX=0.75 scaleY=0.75 alpha=0]
[anim name=player alpha=1 time=500]
[wait time=1000]

tmlib.novel.js は, tmlib.js でノベルゲームを
簡単に作れるようにするためのプラグインだよ.[l]
[cm]

まだ開発途中だけどわりと動いているよ.[r][l]
キリキリスクリプトってやつに似せて作ってあるよ.[r][l]
でも他にも色々やれるようになっていく予定だよ.[l]
[cm]

これからガンガン開発していくよ.[r][l]
協力してくれると嬉しいな.[l]
[cm]

// プレイヤーを非表示
[anim name=player alpha=0 time=500]
[wait time=1000]
[delete name=player]

// *start タグにジャンプ
//[jump target=*start]

// bgm を停止
[music_stop name=bgm]

[s]
```


ちなみにtmlib.novel.jsで次の制御が抜けてて無限コールバックになっちゃってたので修正が必要です。

```tmlib.novel.js(v0.1.0)
music_stop: function(app, params) {
	        tm.asset.Manager.get(params.name).stop();
	        this.next();// 抜けてる
},
```