Categories
JavaScript tmlib.js Tutorial

03:「ボタンや文字など色々表示してみよう」 – JavaScriptライブラリ「tmlib.js」でシンプルなタッチゲームを超簡単に作るチュートリアル

ラベル(文字)を表示してみよう

サンプル

コードの解説

変数UI_DATAに文字を描画するのに必要なデータを作っておきます。

/**
 * TitleScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはTitleSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    ns.TitleScene = tm.createClass({
        superClass : tm.app.TitleScene,

        init : function() {
            this.superInit({
                title :  "タッチゲーム制作チュートリアル",
                width :  ns.SCREEN_WIDTH,
                height : ns.SCREEN_HEIGHT
            });

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.MainScene());
            });
        },
    });

})(game);

文字の色や、フォントのサイズ、表示する場所など指定できますね。文字に関することを全てセッティングします。セッティングしたデータが出来れば、次の一行で画面に表示することができます。

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

ついでなので、現在どのシーンなのか分かるように、全てのシーンにラベルを表示しておきましょう。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.EndScene());
            });
        },
    });

})(game);
/**
 * EndScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはEndSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var RESULT_PARAM = {
            score: 256,
            msg:      "【タッチゲーム制作チュートリアル】",
            hashtags: ["omatoro", "tmlibチュートリアル"],
            url:      "http://testcording.com",
            width:    ns.SCREEN_WIDTH,
            height:   ns.SCREEN_HEIGHT,
            related:  "tmlib.js Tutorial testcording",
    };

    ns.EndScene = tm.createClass({
        superClass : tm.app.ResultScene,

        init : function() {
            // スコア
            this.superInit(RESULT_PARAM);

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.TitleScene());
            });
        },
    });

})(game);

ボタンを表示してみよう

サンプル

コードの解説

EndSceneで使われているボタンを作ってみましょう。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var BUTTON_SIZE  = 128;
    var BUTTON_COLOR = "green";
    var BUTTON_TEXT  = "ボタンです";
    var BUTTON_X     = ns.SCREEN_WIDTH/2;
    var BUTTON_Y     = ns.SCREEN_HEIGHT/2;

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.EndScene());
            });

            // ボタンを作る
            var button = tm.app.GlossyButton(BUTTON_SIZE, BUTTON_SIZE, BUTTON_COLOR, BUTTON_TEXT);
            // 表示位置
            button.position.set(BUTTON_X, BUTTON_Y);
            // 表示する
            this.addChild(button);
        },
    });

})(game);

GlossyButtonというクラスを使うと、シンプルで綺麗なボタンが簡単に作ることができます。しかもマウスを重ねたりタッチすると光ります。ボタンのサイズや色、中に書くテキストを指定することができます。

            // ボタンを作る
            var button = tm.app.GlossyButton(BUTTON_SIZE, BUTTON_SIZE, BUTTON_COLOR, BUTTON_TEXT);

次のposition.setで表示箇所を指定します。

            // 表示位置
            button.position.set(BUTTON_X, BUTTON_Y);

実際に表示するには、このシーンの子として追加する必要があります。addChild()に追加すると自動で描画してくれると思ったらOKです。

            // 表示する
            this.addChild(button);

ハートを表示してみよう

サンプル

コードの解説

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 128;
    var HEART_X     = ns.SCREEN_WIDTH/2;
    var HEART_Y     = ns.SCREEN_HEIGHT/2;

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.EndScene());
            });

            // ハートを作る
            var heart = tm.app.HeartShape(HEART_SIZE, HEART_SIZE);
            // 表示位置
            heart.position.set(HEART_X, HEART_Y);
            // 表示する
            this.addChild(heart);
        },
    });

})(game);

ボタンと同じ要領で、簡単にハートを書くことができます。このハートを使ってゲームを作っていってみましょう。

 
 

HeartShapeではなく、StarShapeやCircleShapeに名前を変えると星形や円形を簡単に表示できます。サンプルを載せておきますので、弄ってみてくださいね。

Categories
JavaScript tmlib.js Tutorial

04:「ゲームの画面を作ろう」 – JavaScriptライブラリ「tmlib.js」でシンプルなタッチゲームを超簡単に作るチュートリアル

たくさんのハートを表示してみよう

サンプル

コードの解説

ループを使ってまとめてハートを作ってみます。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.EndScene());
            });

            // たくさんハートを作る
            for (var i = 0; i < HEART_NUM; ++i) {
                // ハートを作る
                var heart = tm.app.HeartShape(HEART_SIZE, HEART_SIZE);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));
                // 表示する
                this.addChild(heart);
            }
        },
    });

})(game);

ハートの位置は、画面の端から端までのランダムな場所です。Math.rand()という関数を使うことで、ランダムな数を取得することができます。一つ気をつけてほしい箇所があります。0からns.SCREEN_WIDTHまでのランダム値になっていないですね。感覚的には以下のようなコードになりそうです。

                // 表示位置
                heart.position.set(
                        Math.rand(0, ns.SCREEN_WIDTH),
                        Math.rand(0, ns.SCREEN_HEIGHT));

しかし、上記のコードだとハートが画面端に見切れて表示されてしまいます。それを防ぐために、ハートの半分サイズ座標を狭めてランダム値を取得しています。

ハートの色を変えてみよう

サンプル

コードの解説

ハートの色もランダムになるようにしてみましょう。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            this.addEventListener("pointingend", function(e) {
                // シーンの遷移
                e.app.replaceScene(ns.EndScene());
            });

            // たくさんハートを作る
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));
                // 表示する
                this.addChild(heart);
            }
        },
    });

})(game);

RGBA値で完全にランダムな値にしてしまうと、真っ黒なハートやどす黒いハートばかり出てしまうのでHSLAという表記法を利用しています。HSLAについては特に解説はしませんので、別途調べてみてください。

Categories
JavaScript tmlib.js Tutorial

05:「ゲームの処理を作ろう」 – JavaScriptライブラリ「tmlib.js」でシンプルなゲームを超簡単に作るチュートリアル

ハートをタッチしたら消えるようにしよう

サンプル

コードの解説

ハートをタッチ(or クリック)した時の処理を追加してみましょう。処理を作るヒントは、「シーンをタッチした時の処理」です。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // 画面(シーンの描画箇所)をタッチした時の動作
            // this.addEventListener("pointingend", function(e) {
            //     // シーンの遷移
            //     e.app.replaceScene(ns.EndScene());
            // });

            // たくさんハートを作る
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));

                // ハートをタッチした時の処理を作る
                heart.interaction.enabled = true;           // ヒット判定フラグをON
                heart.interaction.boundingType = "circle";  // 円形のヒット判定を行う
                heart.addEventListener("pointingend", function() {
                    // 消す
                    this.remove();
                });

                // 表示する
                this.addChild(heart);
            }
        },
    });

})(game);

シーンをタッチした時の処理と同じく、addEventListener()関数を使います。違うのは、addEventListenerの左側に書いてある変数が、thisではなく、heartであることです。

                heart.addEventListener("pointingend", function() {
                    // 消す
                    this.remove();
                });

こうすることで、heartをタッチした時の処理を書くことができます。ハートを消すときは、remove()関数を使います。タッチしたときにremove()関数を読んであげると、タッチしたときにハートが消えるようになります。

制限時間を作ろう

サンプル

コードの解説

今回は追加する処理が多いですが、めげないでくださいね!

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            },{
                type: "Label",
                name: "limitTimeLabel",
                x: 200,
                y: 120,
                width: ns.SCREEN_WIDTH,
                fillStyle: "white",
                text: " ",
                fontSize: 40,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    var LIMIT_TIME = 300; // 10秒 x 30フレーム = 300

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // たくさんハートを作る
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));

                // ハートをタッチした時の処理を作る
                heart.interaction.enabled = true;           // ヒット判定フラグをON
                heart.interaction.boundingType = "circle";  // 円形のヒット判定を行う
                heart.addEventListener("pointingend", function() {
                    // 消す
                    this.remove();
                });

                // 表示する
                this.addChild(heart);
            }

            // 制限時間
            this.limitTime = LIMIT_TIME;
        },

        update: function (app) {
            // カウントダウンを行う
            --this.limitTime;

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                app.replaceScene(ns.EndScene());
            }
        },
    });

})(game);

複数の処理を追加したので、一つ一つ見ていきます。まず最初に、制限時間を表示するためのラベルを追加しました。以下のコードです。

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            },{
                type: "Label",
                name: "limitTimeLabel",
                x: 200,
                y: 120,
                width: ns.SCREEN_WIDTH,
                fillStyle: "white",
                text: " ",
                fontSize: 40,
                align: "left"
            }]
        }
    };

次に、制限時間を設定するための変数が増えました。

    var LIMIT_TIME = 300; // 10秒 x 30フレーム = 300

ゲームの処理は一秒間に30回行われるので、それを見越して10秒を制限時間に設定したい場合は300となります。この300という値をゲームの実行毎にマイナス1していくことで、10秒経ったのかどうかが分かるようにします。
 
次に、update()という関数が増えました。update()関数は、ゲームの処理毎に呼ばれる関数です。そのため、一秒間に30回呼ばれることになります。

        update: function (app) {
            // カウントダウンを行う
            --this.limitTime;

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                app.replaceScene(ns.EndScene());
            }
        },

カウントダウンを行なって、0になれば勝手にEndSceneに遷移するように処理を作ります。画面に表示する制限時間の計算方法も見ておきます。

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

this.limitTime変数は秒ではありません。ややこしいですが、一秒間に30回処理が行われる上で成り立っている300という数値です。30で割ることで現在の残り時間を取得することができます。”|0″というのはJavaScriptのテクニックの一つで、値を整数にします。割り算してるので小数点以下の数が出てしまいますが、”|0″のテクニックを使うことで整数になります。

全てハートを消したらゲームが終わるようにしよう

サンプル

コードの解説

ハートの数が今いくつなのか分かるように、「グループ」を作って管理するように変更しました。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            },{
                type: "Label",
                name: "limitTimeLabel",
                x: 200,
                y: 120,
                width: ns.SCREEN_WIDTH,
                fillStyle: "white",
                text: " ",
                fontSize: 40,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    var LIMIT_TIME = 300; // 10秒 x 30フレーム = 300

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // たくさんハートを作る
            this.heartGroup = tm.app.CanvasElement();
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));

                // ハートをタッチした時の処理を作る
                heart.interaction.enabled = true;           // ヒット判定フラグをON
                heart.interaction.boundingType = "circle";  // 円形のヒット判定を行う
                heart.addEventListener("pointingend", function() {
                    // 消す
                    this.remove();
                });

                // 表示する
                this.heartGroup.addChild(heart);
            }
            this.addChild(this.heartGroup);

            // 制限時間
            this.limitTime = LIMIT_TIME;
        },

        update: function (app) {
            // カウントダウンを行う
            --this.limitTime;

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                app.replaceScene(ns.EndScene());
            }

            // ハートが全部なくなったらEndSceneに遷移する
            if (this.heartGroup.children.length <= 0) {
                app.replaceScene(ns.EndScene());
            }
        },
    });

})(game);

ハイライトの部分をみてみると、this.addChild()としてシーンに追加するのはグループのみになってますね。そのグループに対してheartをaddChild()するので、シーンから見るとheartは子でなく孫になります。一つグループをかませることにより、heartの数を簡単に取得することができます。

            // ハートが全部なくなったらEndSceneに遷移する
            if (this.heartGroup.children.length <= 0) {
                app.replaceScene(ns.EndScene());
            }

これで、EndSceneに遷移する条件は「ハートが全部無くなる」か、「制限時間が無くなる」場合の2つとなりました。

スコアを表示しよう

サンプル

コードの解説

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            },{
                type: "Label",
                name: "limitTimeLabel",
                x: 200,
                y: 120,
                width: ns.SCREEN_WIDTH,
                fillStyle: "white",
                text: " ",
                fontSize: 40,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    var LIMIT_TIME = 300; // 10秒 x 30フレーム = 300

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // たくさんハートを作る
            this.heartGroup = tm.app.CanvasElement();
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));

                // ハートをタッチした時の処理を作る
                heart.interaction.enabled = true;           // ヒット判定フラグをON
                heart.interaction.boundingType = "circle";  // 円形のヒット判定を行う
                heart.addEventListener("pointingend", function() {
                    // 消す
                    this.remove();
                });

                // 表示する
                this.heartGroup.addChild(heart);
            }
            this.addChild(this.heartGroup);

            // 制限時間
            this.limitTime = LIMIT_TIME;
        },

        update: function (app) {
            // カウントダウンを行う
            --this.limitTime;

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                app.replaceScene(ns.EndScene(0));
            }

            // ハートが全部なくなったらEndSceneに遷移する
            if (this.heartGroup.children.length <= 0) {
                app.replaceScene(ns.EndScene(this.limitTime));
            }
        },
    });

})(game);

EndSceneに現在残っているリミット時間を渡すようにしています。そして、EndSceneに渡したデータをどうするのかと言うと……。

/**
 * EndScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはEndSceneです。",
                fontSize: 30,
                align: "left"
            }]
        }
    };

    var RESULT_PARAM = {
            score: 256,
            msg:      "【タッチゲーム制作チュートリアル】",
            hashtags: ["omatoro", "tmlibチュートリアル"],
            url:      "http://testcording.com",
            width:    ns.SCREEN_WIDTH,
            height:   ns.SCREEN_HEIGHT,
            related:  "tmlib.js Tutorial testcording",
    };

    ns.EndScene = tm.createClass({
        superClass : tm.app.ResultScene,

        init : function(leftTime) {
            // スコア計算
            RESULT_PARAM.score = (leftTime * 100) |0;

            // スコア
            this.superInit(RESULT_PARAM);

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // // 画面(シーンの描画箇所)をタッチした時の動作
            // this.addEventListener("pointingend", function(e) {
            //     // シーンの遷移
            //     e.app.replaceScene(ns.TitleScene());
            // });
        },

        // Backボタンを押したらTitleSceneに戻る
        onnextscene: function (e) {
            e.target.app.replaceScene(ns.TitleScene());
        },
    });

})(game);

init関数に引数を記述しています。こうすると、クラスを呼び出した時にinit関数がデータを受け取ることができます。で、受け取ったデータはそのままスコアの計算に使っています。

            // スコア計算
            RESULT_PARAM.score = (leftTime * 100) |0;

これでスコアを作ることができました。ゲームの処理はこれで出来上がりです!お疲れ様でした!!次はゲームを彩ってくれる”音”を入れてみたいと思います。

もうちょっと詳しく解説

よく見ると……

        // Backボタンを押したらTitleSceneに戻る
        onnextscene: function (e) {
            e.target.app.replaceScene(ns.TitleScene());
        },

この処理も新たに追加していますね。これはコメントの通り、Backボタンを押した時の動作を書くための処理です。今まで画面をタッチしたらTitleSceneに戻っていましたが、Backボタンを押した時のみTitleSceneに行くよう変更しています。

Categories
JavaScript tmlib.js Tutorial

Ex:「音をつけよう」 – JavaScriptライブラリ「tmlib.js」でシンプルなゲームを超簡単に作るチュートリアル

BGMを鳴らしてみよう

サンプル

コードの解説

まず、音楽を入れるディレクトリを作っておきます。jsフォルダと同階層に「rsc」という名前のディレクトリを用意しています。音のファイルも用意しています。では音を読み込んでみましょう。音を読み込む用のコードも別のファイルにしておきます。名前はresource.jsです。

/**
 * リソースの読み込み
 */
tm.preload(function() {

	// 音
	tm.sound.SoundManager.add("bgm", "http://rawgithub.com/omatoro/tmlib.js_tutorial_TouchGame/master/EX_%E9%9F%B3%E3%82%92%E9%B3%B4%E3%82%89%E3%81%9D%E3%81%86/01_BGM/rsc/Comical01_Koya.mp3");

});

新しくresource.jsというファイルを用意しました。tm.preload()関数内に読み込みたいファイルを記述します。次は読み込んだデータの呼び出し方です。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            },{
                type: "Label",
                name: "limitTimeLabel",
                x: 200,
                y: 120,
                width: ns.SCREEN_WIDTH,
                fillStyle: "white",
                text: " ",
                fontSize: 40,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    var LIMIT_TIME = 300; // 10秒 x 30フレーム = 300

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // たくさんハートを作る
            this.heartGroup = tm.app.CanvasElement();
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));

                // ハートをタッチした時の処理を作る
                heart.interaction.enabled = true;           // ヒット判定フラグをON
                heart.interaction.boundingType = "circle";  // 円形のヒット判定を行う
                heart.addEventListener("pointingend", function() {
                    // 消す
                    this.remove();
                });

                // 表示する
                this.heartGroup.addChild(heart);
            }
            this.addChild(this.heartGroup);

            // 制限時間
            this.limitTime = LIMIT_TIME;

            // BGM再生
            this.bgm = tm.sound.SoundManager.get("bgm");
            this.bgm.loop = true;
            this.bgm.play();
        },

        update: function (app) {
            // カウントダウンを行う
            --this.limitTime;

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                this.bgm.stop();
                app.replaceScene(ns.EndScene(0));
            }

            // ハートが全部なくなったらEndSceneに遷移する
            if (this.heartGroup.children.length <= 0) {
                this.bgm.stop();
                app.replaceScene(ns.EndScene(this.limitTime));
            }
        },
    });

})(game);

tm.sound.SoundManager.get()関数を使うことで、読み込んだデータを取り出すことができます。取り出したデータをthis.bgm変数に入れ込み、ループして鳴るように設定しています。play()関数を呼べば音がなります。音を出すにはplay()関数を呼ぶだけです。簡単ですね。EndSceneに遷移する前に音を止めています。

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                this.bgm.stop();
                app.replaceScene(ns.EndScene(0));
            }

            // ハートが全部なくなったらEndSceneに遷移する
            if (this.heartGroup.children.length <= 0) {
                this.bgm.stop();
                app.replaceScene(ns.EndScene(this.limitTime));
            }

EndSceneではまた別の音を鳴らしたい!と思ったら、同じように追加してみてくださいね。

SE(サウンドエフェクト)を鳴らしてみよう

サンプル

コードの解説

SE用の音楽データを追加し、resource.jsファイルを書き換えます。

/**
 * リソースの読み込み
 */
tm.preload(function() {
	// 音
	tm.sound.SoundManager.add("bgm", "http://rawgithub.com/omatoro/tmlib.js_tutorial_TouchGame/master/EX_%E9%9F%B3%E3%82%92%E9%B3%B4%E3%82%89%E3%81%9D%E3%81%86/02_SE/rsc/Comical01_Koya.mp3");
	tm.sound.SoundManager.add("se",  "http://rawgithub.com/omatoro/tmlib.js_tutorial_TouchGame/master/EX_%E9%9F%B3%E3%82%92%E9%B3%B4%E3%82%89%E3%81%9D%E3%81%86/02_SE/rsc/%5BSystem%5DCursor03_panop.ogg");
});

次は、ハートを消した時に音がなるようにMainSceneを修正してみましょう。

/**
 * MainScene
 */
(function(ns) {

    // ラベルのリスト
    var UI_DATA = {
        LABELS: {
            children: [{
                type: "Label",
                name: "label",
                x: 40,
                y: 80,
                width: ns.SCREEN_WIDTH,
                fillStyle: "red",
                text: "ここはMainSceneです。",
                fontSize: 30,
                align: "left"
            },{
                type: "Label",
                name: "limitTimeLabel",
                x: 200,
                y: 120,
                width: ns.SCREEN_WIDTH,
                fillStyle: "white",
                text: " ",
                fontSize: 40,
                align: "left"
            }]
        }
    };

    var HEART_SIZE  = 64;
    var HEART_NUM   = 10;
    var HEART_PARAM = {
        fillStyle: "pink",
    };

    var LIMIT_TIME = 300; // 10秒 x 30フレーム = 300

    ns.MainScene = tm.createClass({
        superClass : tm.app.Scene,

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

            // ラベル表示
            this.fromJSON(UI_DATA.LABELS);

            // たくさんハートを作る
            this.heartGroup = tm.app.CanvasElement();
            for (var i = 0; i < HEART_NUM; ++i) {
                // 色をつくる
                HEART_PARAM.fillStyle = tm.graphics.Color.createStyleHSLA(Math.rand(0, 360), 95, 75, 0.8);

                // ハートを作る
                var heart = tm.app.HeartShape(
                        HEART_SIZE, 
                        HEART_SIZE, 
                        HEART_PARAM);
                // 表示位置
                heart.position.set(
                        Math.rand(HEART_SIZE/2, ns.SCREEN_WIDTH  - HEART_SIZE/2),
                        Math.rand(HEART_SIZE/2, ns.SCREEN_HEIGHT - HEART_SIZE/2));

                // ハートをタッチした時の処理を作る
                heart.interaction.enabled = true;           // ヒット判定フラグをON
                heart.interaction.boundingType = "circle";  // 円形のヒット判定を行う
                heart.addEventListener("pointingend", function() {
                    // 音を出す
                    tm.sound.SoundManager.get("se").clone().play();
                    // 消す
                    this.remove();
                });

                // 表示する
                this.heartGroup.addChild(heart);
            }
            this.addChild(this.heartGroup);

            // 制限時間
            this.limitTime = LIMIT_TIME;

            // BGM再生
            this.bgm = tm.sound.SoundManager.get("bgm");
            this.bgm.loop = true;
            this.bgm.play();
        },

        update: function (app) {
            // カウントダウンを行う
            --this.limitTime;

            // 制限時間を表示する
            this.limitTimeLabel.text = "残り時間 : " + ((this.limitTime / 30) |0);

            // 制限時間がなくなったらEndSceneに遷移する
            if (this.limitTime <= 0) {
                this.bgm.stop();
                app.replaceScene(ns.EndScene(0));
            }

            // ハートが全部なくなったらEndSceneに遷移する
            if (this.heartGroup.children.length <= 0) {
                this.bgm.stop();
                app.replaceScene(ns.EndScene(this.limitTime));
            }
        },
    });

})(game);

これで音が鳴るようになりました。本当はもっと大変なんですけど、tmlib.jsが準備してくれているおかげですね。

Categories
JavaScript tmlib.js

JavaScriptライブラリ「tmlib.js」でローグライクを作ってみた

JavaScriptを用いてローグライクを作ってみました。ブラウザ上で動くので、iPhoneやパソコンでも動きます。
厳密にいえばローグどころかローグライクですらないので、ローグライク風(?)なゲームって言ったほうがいいでしょうか。

 

 

Categories
HTML JavaScript

GithubからJavaScriptを読み込み時は専用のドメインから!

chromeで以下のようなエラーが出た場合の解決方法がいまいち調べても分かりませんでした。

Refused to execute script from 'https://raw.github.com/mrdoob/stats.js/master/src/Stats.js' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled. 

ブラウザがデータをロードする際に脆弱性があるそうで、セキュリティ重視のため弾いてるようです。

以下のようにリンクを記述すると解決します。

<script src="http://rawgithub.com/mrdoob/stats.js/master/src/Stats.js"></script>

追記:現在上記の書き方は、テスト用やデモ用でサクッとやりたいときだけにしてくれとのことです。
CDNとして使いたいときは以下の書き方が推奨されています。

転載元 https://rawgit.com/faq

<script src="https://cdn.rawgit.com/mrdoob/stats.js/master/src/Stats.js"></script>

githubは、生データへアクセスするためのドメインを用意したみたいで、こっちからアクセスすればエラーが収まります。
無料のサービスのようです。githubとは関連はないそうでした。

Is RawGit associated with GitHub?
Nope, RawGit is not associated with GitHub, Inc. in any way.

画像などのデータも同じエラーが起きることがあるようで、同じ方法で解決できます。

情報が無かったため、簡単なメモ書きですが参考になればと思います。

Categories
JavaScript tmlib.js

JavaScript+canvasでiPhone風ピッカーを作ってみた – tmlib.js

tmlib.js を利用したゲームを制作する中で、メニューを作っておきたかったため制作しました。iPhoneのピッカーは操作感が素晴らしく、初めてiPhoneを買ったときはしばらくピッカーで遊んでいた(?)こともあります。今回作ったのは、いわゆるリバースエンジニアリングってやつですね。 tmlib.js を使っていますので、スマートフォンでも動くと思います。

 

Categories
JavaScript tmlib.js

サクッと脳トレ!n-back課題をウェブで作ってみた

ウェブ上でサクッと遊べるn-back課題を作ってみましたので、紹介します。

 

 

スマートフォン(iPhone4Sのみテスト済み)や、PCでのブラウザでも動きますのでサクッと遊べます。

 

Categories
JavaScript Node.js

初心者でも安心!?Node.jsをインストールするなら仮想サーバを使おう

Node.jsを触っておきたいなと思いつつ、MacBookAirにインストールする時えらく苦労したのでもっと簡単にローカルで実験する方法を探していました。タイトル通り、仮想サーバを作ればすんなりインストール+サンプル実行までできたのでメモとして残しておこうと思います。

 

 

Categories
JavaScript tmlib.js WebAudio

JavaScriptでオーディオビジュアライザを作ってみた

Web Audio API という、ブラウザ上で音を解析したり鳴らしたりできるプログラムを利用してオーディオビジュアライザを作ってみました。