Categories
game JavaScript tmlib.js Tutorial

Ex:「音をつけよう & iPhoneを傾けたら移動するようにしてみよう」 – tmlib.js入門用チュートリアル!避けゲーを作ってみよう

BGMを再生しよう

サンプル

コードの解説

tmlib.jsは音の再生もサポートしているので、BGMを鳴らしてみます。

/**
 * ゲーム用定数作成
 */
var SCREEN_WIDTH  = 960;
var SCREEN_HEIGHT = 640;
var RESULT_PARAM = {
        score: 256,
        msg:      "【避けゲー制作チュートリアル】",
        hashtags: ["omatoro", "tmlibチュートリアル"],
        url:      "http://omatoro.github.io/tmlib.js_tutorial_avoidgame/",
        width:    SCREEN_WIDTH,
        height:   SCREEN_HEIGHT,
        related:  "tmlib.js Tutorial testcording",
};
var UI_DATA = {
    main: { // MainScene用ラベル
        children: [{
            type: "Label",
            name: "timeLabel",
            x: 200,
            y: 120,
            width: SCREEN_WIDTH,
            fillStyle: "white",
            // text: "残り時間を表示する",
            text: " ",
            fontSize: 40,
            align: "left"
        }]
    }
};
var PLAYER_WIDTH  = 20;
var PLAYER_HEIGHT = 16;
var PLAYER_GROUND_LIMIT_LEFT  = PLAYER_WIDTH/2;
var PLAYER_GROUND_LIMIT_RIGHT = SCREEN_WIDTH - PLAYER_WIDTH/2;
var ENEMY_WIDTH  = 38;
var ENEMY_HEIGHT = 30;

/**
 * リソースの読み込み
 */
var ASSETS = {
    "player":   "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/[Animal]Chicken.png",
    "playerSS": "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/playerSS.tmss",
    "enemy":    "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/[Monster]Dragon_B_pochi.png",
    "bgm":      "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/Comical01_Koya_short2.mp3",
    "backMap":  "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/map.png",
};

/**
 * ゲーム起動処理
 */
tm.main(function() {
    // アプリケーション作成
    var app = tm.app.CanvasApp("#world");
    app.resize(SCREEN_WIDTH, SCREEN_HEIGHT); // 画面サイズに合わせる
    app.fitWindow(); // リサイズ対応
    app.background = "rgb(0, 0, 0)"; // 背景色をセット

    var loadingScene = tm.app.LoadingScene({
        assets: ASSETS,
        nextScene: TitleScene,
        width: SCREEN_WIDTH,
        height: SCREEN_HEIGHT,
    });

    // シーンの切り替え
    app.replaceScene(loadingScene);

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


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

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

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


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

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

        // BGM再生
        this.bgm = tm.asset.AssetManager.get("bgm");
        this.bgm.setVolume(1.0).setLoop(true).play();

        // Map
        this.map = tm.app.Sprite("backMap", SCREEN_WIDTH, SCREEN_HEIGHT).addChildTo(this);
        this.map.position.set(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);

        // Player
        this.player = Player().addChildTo(this);
        this.player.position.set(150, 600);

        // enemy
        this.enemyGroup = tm.app.CanvasElement().addChildTo(this);

        // スコア用カウントアップ
        this.timer = 0;

        // ラベル表示
        this.fromJSON(UI_DATA.main);
    },

    update: function (app) {
        // カウントアップを行う
        ++this.timer;

        // 制限時間を表示する
        this.timeLabel.text = "生き残ってる時間 : " + ((this.timer / 30) |0);

        // 敵の生成(難易度をどんどん上げる)
        if (this.timer % 30 === 0) {
        	for (var i = 0, n = (this.timer / 300); i < n; ++i) {
                var enemy = Enemy().addChildTo(this.enemyGroup);
                enemy.x = Math.rand(0, SCREEN_WIDTH);
                enemy.y = 0 - enemy.height;
        	}
        }

        var self = this;
        var ec = this.enemyGroup.children;
        ec.each(function(enemy) {
            if (self.player.isHitElement(enemy)) {
                self.bgm.stop();
                app.replaceScene(EndScene(self.timer))
            };
        });
    },
});


/**
 * EndScene
 */
tm.define("EndScene", {
    superClass : "tm.app.ResultScene",

    init : function(time) {
        // スコア計算
        RESULT_PARAM.score = (Math.floor(time*100/30)/100) + "秒生き残ることができました。";

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

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


/*
 * player
 */
tm.define("Player", {
    superClass: "tm.app.AnimationSprite",

    init: function () {
        this.superInit("playerSS", PLAYER_WIDTH*4, PLAYER_HEIGHT*4);
        // this.gotoAndPlay("left");
        // 移動の方向を保持
        this.direct = "left";
    },

    moveLimit: function () {
        // 画面からはみ出ないようにする
        if (this.x < PLAYER_GROUND_LIMIT_LEFT) {
            this.x = PLAYER_GROUND_LIMIT_LEFT;
        }
        if (this.x > PLAYER_GROUND_LIMIT_RIGHT) {
            this.x = PLAYER_GROUND_LIMIT_RIGHT;
        }
    },

    clickLeft: function () {
        this.gotoAndPlay("left");
        this.x -= 4;
    },

    clickRight: function () {
        this.gotoAndPlay("right");
        this.x += 4;
    },

    update: function (app) {
        // 移動処理
        if (app.pointing.getPointingStart()) {
            this.direct = (this.direct === "left") ? "right" : "left";
        }
        switch (this.direct) {
            case "left":
                this.clickLeft();
                break;
            case "right":
                this.clickRight();
                break;
        }
        // 移動の限界
        this.moveLimit();
    },
});


/*
 * enemy
 */
tm.define("Enemy", {
    superClass: "tm.app.Sprite",

    init: function() {
        this.superInit("enemy", ENEMY_WIDTH*4, ENEMY_HEIGHT*4);
        this.speed = Math.rand(6, 12);
    },

    update: function() {
        this.y += this.speed;

        // 画面から見えなくなったら消す
        if (this.y > SCREEN_HEIGHT + this.height) {
            this.remove();
        }
    }
});

画像と同じように音楽もロードすることができます。MainSceneが開始するときにBGMがなり始めるようにします。

        // BGM再生
        this.bgm = tm.asset.AssetManager.get("bgm");
        this.bgm.setVolume(1.0).setLoop(true).play();

ボリュームやBGMをループして再生する設定など行った後、play関数で音の再生を開始します。

 

このままだと、EndSceneになってもBGMが鳴り続けてしまいます。EndSceneに遷移する前にBGMをストップしておきます。

                self.bgm.stop();

ジャイロセンサーを使って、スマートフォンを傾けても移動できるようにしよう

サンプル

コードの解説

ジャイロセンサーとは、iPhoneの傾きを検知するセンサーです。tmlib.jsでは、このセンサーをゲームに応用しやすいようにしてくれています。

/**
 * ゲーム用定数作成
 */
var SCREEN_WIDTH  = 960;
var SCREEN_HEIGHT = 640;
var RESULT_PARAM = {
        score: 256,
        msg:      "【避けゲー制作チュートリアル】",
        hashtags: ["omatoro", "tmlibチュートリアル"],
        url:      "http://omatoro.github.io/tmlib.js_tutorial_avoidgame/",
        width:    SCREEN_WIDTH,
        height:   SCREEN_HEIGHT,
        related:  "tmlib.js Tutorial testcording",
};
var UI_DATA = {
    main: { // MainScene用ラベル
        children: [{
            type: "Label",
            name: "timeLabel",
            x: 200,
            y: 120,
            width: SCREEN_WIDTH,
            fillStyle: "white",
            text: " ",
            fontSize: 40,
            align: "left"
        }]
    }
};
var PLAYER_WIDTH  = 20;
var PLAYER_HEIGHT = 16;
var PLAYER_GROUND_LIMIT_LEFT  = PLAYER_WIDTH/2;
var PLAYER_GROUND_LIMIT_RIGHT = SCREEN_WIDTH - PLAYER_WIDTH/2;
var ENEMY_WIDTH  = 38;
var ENEMY_HEIGHT = 30;

/**
 * リソースの読み込み
 */
var ASSETS = {
    "player":   "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/[Animal]Chicken.png",
    "playerSS": "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/playerSS.tmss",
    "enemy":    "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/[Monster]Dragon_B_pochi.png",
    "bgm":      "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/Comical01_Koya_short2.mp3",
    "backMap":  "http://rawgithub.com/omatoro/tmlib.js_tutorial_avoidgame/gh-pages/rsc/map.png",
};


/**
 * ゲーム起動処理
 */
tm.main(function() {
    // アプリケーション作成
    var app = tm.app.CanvasApp("#world");
    app.resize(SCREEN_WIDTH, SCREEN_HEIGHT); // 画面サイズに合わせる
    app.fitWindow(); // リサイズ対応
    app.background = "rgb(0, 0, 0)"; // 背景色をセット

    var loadingScene = tm.app.LoadingScene({
        assets: ASSETS,
        nextScene: TitleScene,
        width: SCREEN_WIDTH,
        height: SCREEN_HEIGHT,
    });

    // シーンの切り替え
    app.replaceScene(loadingScene);

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


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

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

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


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

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

        // BGM再生
        this.bgm = tm.asset.AssetManager.get("bgm");
        this.bgm.setVolume(1.0).setLoop(true).play();

        // Map
        this.map = tm.app.Sprite("backMap", SCREEN_WIDTH, SCREEN_HEIGHT).addChildTo(this);
        this.map.position.set(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);

        // Player
        this.player = Player().addChildTo(this);
        this.player.position.set(150, 600);

        // enemy
        this.enemyGroup = tm.app.CanvasElement().addChildTo(this);

        // スコア用カウントアップ
        this.timer = 0;

        // ラベル表示
        this.fromJSON(UI_DATA.main);
    },

    update: function (app) {
        // カウントアップを行う
        ++this.timer;

        // 制限時間を表示する
        this.timeLabel.text = "生き残ってる時間 : " + ((this.timer / 30) |0);

        // 敵の生成(難易度をどんどん上げる)
        if (this.timer % 30 === 0) {
            for (var i = 0, n = (this.timer / 300); i < n; ++i) {
                var enemy = Enemy().addChildTo(this.enemyGroup);
                enemy.x = Math.rand(0, SCREEN_WIDTH);
                enemy.y = 0 - enemy.height;
            }
        }

        var self = this;
        var ec = this.enemyGroup.children;
        ec.each(function(enemy) {
            if (self.player.isHitElement(enemy)) {
                self.bgm.stop();
                app.replaceScene(EndScene(self.timer))
            };
        });
    },
});


/**
 * EndScene
 */
tm.define("EndScene", {
    superClass : "tm.app.ResultScene",

    init : function(time) {
        // スコア計算
        RESULT_PARAM.score = (Math.floor(time*100/30)/100) + "秒生き残ることができました。";

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

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


/*
 * player
 */
tm.define("Player", {
    superClass: "tm.app.AnimationSprite",

    init: function () {
        this.superInit("playerSS", PLAYER_WIDTH*4, PLAYER_HEIGHT*4);
        // 移動の方向を保持
        this.direct = "left";
        // スマホかどうか判断
        this.isMobile = tm.isMobile;
        // スマホだったら加速度を使うので、タッチ入力での移動を行わない
        this.update = (this.isMobile) ? this.updateMobile : this.updateNotMobile;
    },

    moveLimit: function () {
        // 画面からはみ出ないようにする
        if (this.x < PLAYER_GROUND_LIMIT_LEFT) {
            this.x = PLAYER_GROUND_LIMIT_LEFT;
        }
        if (this.x > PLAYER_GROUND_LIMIT_RIGHT) {
            this.x = PLAYER_GROUND_LIMIT_RIGHT;
        }
    },

    clickLeft: function () {
        this.gotoAndPlay("left");
        this.x -= 4;
    },

    clickRight: function () {
        this.gotoAndPlay("right");
        this.x += 4;
    },

    updateNotMobile: function (app) {
        // 移動処理
        if (app.pointing.getPointingStart()) {
            this.direct = (this.direct === "left") ? "right" : "left";
        }
        switch (this.direct) {
            case "left":
                this.clickLeft();
                break;
            case "right":
                this.clickRight();
                break;
        }
        // 移動の限界
        this.moveLimit();
    },

    updateMobile: function (app) {
        // 移動処理:モバイルなら加速度センサーを利用
        var gravity = app.accelerometer.gravity;
        this.x -= gravity.y * 1.7;

        // 移動方向によってアニメーション
        if (gravity.y > 0) { this.gotoAndPlay("left"); }
        else               { this.gotoAndPlay("right"); }

        // 移動の限界
        this.moveLimit();
    },
});

/*
 * enemy
 */
tm.define("Enemy", {
    superClass: "tm.app.Sprite",

    init: function() {
        this.superInit("enemy", ENEMY_WIDTH*4, ENEMY_HEIGHT*4);
        this.speed = Math.rand(6, 12);
    },

    update: function() {
        this.y += this.speed;

        // 画面から見えなくなったら消す
        if (this.y > SCREEN_HEIGHT + this.height) {
            this.remove();
        }
    }
});

しかし、プレイヤークラスのupdateを上記の処理にそのまま書き換えてしまうとPCではプレイヤーを操作することはできません。その対策として、PC用のupdateとスマートフォン用のupdateを別に作っておきます。そして、スマートフォンなのかPCなのかを判断してupdateを適切にセットすると、とりあえずiPhoneとPCの区別をつけることができます。

        // スマホかどうか判断
        this.isMobile = tm.isMobile;
        // スマホだったら加速度を使うので、タッチ入力での移動を行わない
        this.update = (this.isMobile) ? this.updateMobile : this.updateNotMobile;

「正確にジャイロセンサーが付いていたら、ジャイロセンサーを使った操作に切り替える」という処理ではないので気をつけてくださいね。

 
 

これでチュートリアルは終了です。お疲れ様でした!落ちゲーのゲームも色々処理を追加しようと思えばたくさん思いつくとおもいます。このチュートリアルでゲームを作り始めてくれたりするととても嬉しいです。

Leave a Reply

Your email address will not be published. Required fields are marked *