Quantcast
Channel: TM Life » JavaScript
Viewing all articles
Browse latest Browse all 10

tmlib.js で今流行のフラットデザインを使ったタッチゲームを作ろう – Step02 ピースのタッチ処理とゲームクリア処理を実装しよう

$
0
0

今回は, ピースをタッチした際にひっくり返るようにして, 更にすべてタッチし終わったらスコアを表示するようにします.

この Step でなんとなくゲームとして遊べるようになります.

Table of contents

チュートリアル目次

前半

後半

up

サンプル

今回作るサンプルです.

タッチするとひっくり返ってグレイになるのがわかると思います. また, 全てタッチし終わると掛かった時間が alert されます.

up

ソースコード

main.js

スクリプト部分のコードです. 追加した箇所のコードはハイライトされています.

Piecedisable というメソッドを追加しています.

更に MainScenePiece を生成した際に, onpointingstart というプロパティに関数を登録しています.

これでタッチ時にこのメソッドが呼ばれるようになります.

詳しい解説は下へ.

/*
 * main.js
 */

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

var PIECE_NUM_X     = 5;                // ピースの列数
var PIECE_NUM_Y     = 5;                // ピースの行数
var PIECE_NUM       = PIECE_NUM_X*PIECE_NUM_Y;  // ピース数
var PIECE_OFFSET_X  = 90;               // ピースオフセットX 
var PIECE_OFFSET_Y  = 240;              // ピースオフセットY
var PIECE_WIDTH     = 120;              // ピースの幅
var PIECE_HEIGHT    = 120;              // ピースの高さ

var FONT_FAMILY_FLAT= "'Helvetica-Light' 'Meiryo' sans-serif";  // フラットデザイン用フォント

/*
 * main
 */
tm.main(function() {
    // アプリケーションセットアップ
    var app = tm.app.CanvasApp("#world");       // 生成
    app.resize(SCREEN_WIDTH, SCREEN_HEIGHT);    // サイズ(解像度)設定
    app.fitWindow();                            // 自動フィッティング有効
    app.background = "rgba(250, 250, 250, 1.0)";// 背景色

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

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

/*
 * ゲームシーン
 */
tm.define("GameScene", {
    superClass: "tm.app.Scene",

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

        var self = this;

        // カレント数
        self.currentNumber = 1;

        // ピースグループ
        this.pieceGroup = tm.app.CanvasElement();
        this.addChild(this.pieceGroup);

        // 数字配列
        var nums = [].range(1, PIECE_NUM+1);  // 1~25
        nums.shuffle(); // シャッフル

        // ピースを作成
        for (var i=0; i<PIECE_NUM_Y; ++i) {
            for (var j=0; j<PIECE_NUM_X; ++j) {
                // 数値
                var number = nums[ i*PIECE_NUM_X+j ];
                // ピースを生成してピースグループに追加
                var piece = Piece(number).addChildTo(this.pieceGroup);
                // 座標を設定
                piece.x = j * 125 + PIECE_OFFSET_X;
                piece.y = i * 125 + PIECE_OFFSET_Y;
                // タッチ時のイベントリスナーを登録
                piece.onpointingstart = function() {
                    // 正解かどうかの判定
                    if (this.number === self.currentNumber) {
                        // クリアかどうかの判定
                        if (self.currentNumber === PIECE_NUM) {
                            // 結果表示
                            var time = (self.app.frame/self.app.fps)|0;
                            alert("GameClear: {0}".format(time));
                        }
                        self.currentNumber += 1;// インクリメント
                        this.disable();         // ボタン無効
                    }
                };
            }
        }
    },
});


/*
 * ピースクラス
 */
tm.define("Piece", {
    superClass: "tm.app.Shape",

    init: function(number) {
        this.superInit(PIECE_WIDTH, PIECE_HEIGHT);
        // 数値をセット
        this.number = number;

        this.setInteractive(true);
        this.setBoundingType("rect");

        var angle = tm.util.Random.randint(0, 360);
        this.canvas.clearColor("hsl({0}, 80%, 70%)".format(angle));

        this.label = tm.app.Label(number).addChildTo(this);
        this.label
            .setFontSize(70)
            .setFontFamily(FONT_FAMILY_FLAT)
            .setAlign("center")
            .setBaseline("middle");
    },

    disable: function() {
        this.setInteractive(false);

        var self = this;
        this.tweener
            .clear()
            .to({scaleX:0}, 100)
            .call(function() {
                self.canvas.clearColor("rgb(100, 100, 100)");
            }.bind(this))
            .to({scaleX:1, alpha:0.5}, 100)
    }
});

up

解説

タッチ判定を無効にする

setInteractionve() メソッドに false を渡して実行することで タッチ判定を無効化することができます.

こうすることで pointingstart, pointingmove, pointingend といった イベントが発火されなくなります.

disable: function() {
    this.setInteractive(false);

Tweener を使ってピースをタッチしたときにアニメーションさせよう

tmlib.js には tweener というクラスがあります.

これを使うことで簡単に複雑なアニメーションをさせることができます. ActionScript の Tweener 的なものですね.

SpriteShape, Label といったインスタンスの tweener プロパティとして使うことができます.

今回, tweener を使った処理について詳しく見て行きましょう.

this.tweener
    .clear()
    .to({scaleX:0}, 100)
    .call(function() {
        self.canvas.clearColor("rgb(100, 100, 100)");
    }.bind(this))
    .to({scaleX:1, alpha:0.5}, 100)

繋げて実行しているのでパッと見, 分かりにくいかもしれませんが 単純に tweener のメソッドを連続で実行しているだけです.

tmlib.js のクラスは基本チェーンメソッドが使えるよう実装してあるので, clear().to(...).call(...); といった形で繋げて実行することができます.

次に処理の方ですが, まず clear() メソッドを呼んで登録されているアニメーションタスクをクリアします.

this.tweener
    .clear()

その次に to() メソッドでアニメーションを登録しています. scaleX を 100 ms かけて 0 にします.

.to({scaleX:0}, 100)

その次に call で登録されたメソッドを呼びます. 今回は色を変更しています.

.call(function() {
    self.canvas.clearColor("rgb(100, 100, 100)");
}.bind(this))

最後にもう一度 scaleX を 1 にすることで 大きさを元に戻しています.

.to({scaleX:1, alpha:0.5}, 100)

これで一旦小さくなって色が変わって元に戻るという アニメーションが再生されます.

ひっくり返ってるように見えませんかね?w

Tweener クラスは他にも wait で処理を待ったり, move で座標を動かしたり, fadeOut でフェードアウトさせたりと便利な機能がたくさんあります.

色々いじって遊んでみてください.

ピースをタッチ時のイベントを登録しよう

setInteractive(true) を実行したインスタンスは, タッチ時に pointingstart というイベントが発行されます.

onpointingstart プロパティに代入した関数もしくは, addEventListener(function() {...}) と登録した関数が実行されます.

// タッチ時のイベントリスナーを登録
piece.onpointingstart = function() {
    ....
};

終了判定を実装しよう

最後に終了判定です.

onpointingstart で実行している処理について見て行きましょう.

// 正解かどうかの判定
if (this.number === self.currentNumber) {
    // クリアかどうかの判定
    if (self.currentNumber === PIECE_NUM) {
        // 結果表示
        var time = (self.app.frame/self.app.fps)|0;
        alert("GameClear: {0}".format(time));
    }
    self.currentNumber += 1;// インクリメント
    this.disable();         // ボタン無効
}

まず, 押されたピースの number プロパティが scene の currentNumber プロパティと 一致するかを判定します.

一致していれば currentNumber を次の数字にして, 押されたピースを disable() メソッドで無効化します.

self.currentNumber += 1;// インクリメント
this.disable();         // ボタン無効

更に, currentNumberPIECE_NUM, つまり最後のピースの数と一致すると 全て押し終わったということになるので終了として 掛かった時間を alert します.

// クリアかどうかの判定
if (self.currentNumber === PIECE_NUM) {
    // 結果表示
    var time = (self.app.frame/self.app.fps)|0;
    alert("GameClear: {0}".format(time));
}

経過時間は app.frame で取得できます. それを app.fps で割れば経過秒数を取得することができます.

これを (...)|0 で整数化して time を求めています.

var time = (self.app.frame/self.app.fps)|0;

更に前回の Step で学んだ format を使って alert メッセージを作成しています.

alert("GameClear: {0}".format(time));

up

まとめ

おさえておいて欲しいポイント

  • tmlib.js のクラスは基本チェーンメソッドが使える
  • Tweener というクラスで簡単にアニメーションできる
  • setInteractive() メソッドでタッチ判定の有効/無効を切り替えられる
  • 経過時間は app.frame で取得でるのでそれを app.fps で割ることで経過秒数を取得できる

up

これで前半の Step は終わりとなります. とても簡単ですよね♪

ここまでで詰まったりうまく動かないなどありましたら 気軽に @phi_jpまでご連絡ください.

次回は後半, ゲームに色々な演出を加えてより ゲームっぽくしていきます.


Viewing all articles
Browse latest Browse all 10

Trending Articles