enchant.jsで遊ぶ

ゲームをサクッと作る場合にどういう選択がいいのか最近考えてた。個人的にはiOSとかAndroidとかスマフォとかでも動くように作れると幸せ。

調べてみると、enchant.jsを使ってHTML5+javascriptなゲームを気軽に作れるみたいなので試してみた。
javascriptは書いたことないけど、Unityとかでも使えるし、最近良く見かける言語だからこれを機会に覚えてみたほうがよさそう。

enchant.jsは以下のサイトから入手できる。
http://enchantjs.com/ja/

試しにライフゲームを書いてみた。ライフゲームのルールはウィキペディア参照。
http://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0

ゲームの核となるmain.jsは以下の通り。

/**
 * enchant.js を使う前に必要な処理。
 */
enchant();

GAME_WIDTH = 640;
GAME_HEIGHT = 640;
GAME_FPS = 3;

CELL_PX = 8;

ALIVE_RATIO = 0.3;

/**
 * HTMLのロードが完了したときに実行する関数。初期設定
 */
window.onload = function () {
    /**
     * ゲームの初期設定
     */
    game = new Game(GAME_WIDTH, GAME_HEIGHT);
    game.fps = GAME_FPS;

    /**
     * ロードされたときの関数
     */
    game.onload = function () {
        /**
         * セルの作成
         */
        cellMap = new Array(GAME_WIDTH/CELL_PX + 2);
        nextCellStateMap = new Boolean(GAME_WIDTH/CELL_PX + 2);
        for (var i=0; i<cellMap.length; i++) {
            cellMap[i] = new Array(GAME_HEIGHT/CELL_PX + 2);
            nextCellStateMap[i] = new Boolean(GAME_WIDTH/CELL_PX + 2);
            for (var j=0; j<cellMap[i].length; j++) {
                cellMap[i][j] = new Cell((i-1)*CELL_PX, (j-1)*CELL_PX);
                nextCellStateMap[i][i] = false;
                // Sceneにセルを登録する
                game.rootScene.addChild(cellMap[i][j]);
            }
        }

        /**
         * セルの生死を初期化する
         */
        for (var i=1; i<cellMap.length-1; i++) {
            for (var j=1; j<cellMap[i].length-1; j++) {
                var rand = Math.random();
                if (rand < ALIVE_RATIO) {
                    cellMap[i][j].update(true);
                    nextCellStateMap[i][j] = true;
                }
            }
        }

        game.rootScene.backgroundColor = 'white';

        /**
         * フレームごとに実行する
         */
        game.rootScene.addEventListener('enterframe', function () {
            /**
             * セルの次状態を確認
             */
            for (var i=1; i<cellMap.length-1; i++) {
                for (var j=1; j<cellMap[i].length-1; j++) {
                    // 隣接セルの生死を確認
                    var aliveCellNum = 0;
                    for (var dx=-1; dx<=1; dx++) {
                        for (var dy=-1; dy<=1; dy++) {
                            if (dx == 0 && dy == 0) continue;
                            if (cellMap[i+dx][j+dy].isAlive) {
                                aliveCellNum += 1;
                            }
                        }
                    }

                    if (!cellMap[i][j].isAlive && aliveCellNum == 3) {
                        // 誕生
                        nextCellStateMap[i][j] = true;
                    }
                    else if (cellMap[i][j].isAlive && (aliveCellNum == 2 || aliveCellNum == 3)) {
                        // 生存
                        nextCellStateMap[i][j] = true;
                    }
                    else if (cellMap[i][j].isAlive && (aliveCellNum == 0 || aliveCellNum == 1)) {
                        // 過疎
                        nextCellStateMap[i][j] = false;
                    }
                    else if (cellMap[i][j].isAlive && (aliveCellNum >= 4)) {
                        // 過密
                        nextCellStateMap[i][j] = false;
                    }
                }
            }

            /**
             * セルの状態を反映
             */
            for (var i=1; i<cellMap.length-1; i++) {
                for (var j=1; j<cellMap[i].length-1; j++) {
                    cellMap[i][j].update(nextCellStateMap[i][j]);
                }
            }
        });
    };

    game.start();
};

/**
 * ライフゲームにおける各シェル
 */
var Cell = enchant.Class.create(enchant.Sprite, {
    /**
     * セルを作成する
     */
    initialize: function (x, y) {
        enchant.Sprite.call(this, CELL_PX, CELL_PX);

        this.isAlive = false;
        this.x = x;
        this.y = y;

        this.backgroundColor = 'white';
    },

    /**
     * 状態更新
     */
    update: function (isAlive) {
        this.isAlive = isAlive;
        if (this.isAlive) {
            this.backgroundColor = 'black';
        } else {
            this.backgroundColor = 'white';
        }
    }
});

動かすにはindex.htmlが必要。enchant.jsのbeginnerのサンプルのindex.htmlがそのまま使えるので、動かす場合は2つを同じフォルダに突っ込んで、enchant.jsのパスだけ変更すればおk。
ソースを見ると、ゲームのSceneにSpriteとかのNodeをぶら下げていくことで一つの画面を作ってるみたい。また、各種Nodeの動作はListenerを使って定義する。

ちなみに動かすとこんな感じ(ブラウザから一部抜き出し、静止画ですが)。

ソース自体は簡単にかけたけど、コード上にエラーがいろいろあって動かすまでに苦労した。javascriptの文法を全然理解してないで書いてるからだけど、javascriptの文法ミスとか変数ミスとかがっつり指摘してくれるようなエディタないかな。Eclipseとか?