2012年01月28日

enchant.js で、インスタンス間の連携をクラス内に記述する

前回の記事、Javaな人向け、enchant.jsのクラスベース実装入門から1週間。引き続きenchant.jsと戯れています。
さて、今回は前回の最後に書いたとおり、

次は、クラスAとクラスBが、お互い連携しながら動作する、というのをどう書けばいいのかなと考え中。

これについて書いてみます。
と言っても、やり方はごく単純でした。むしろ前回詰まったのがケアレスミスレベル。
今回は、Javascriptを知っている方には前回以上に当たり前な話かもしれません。


基本のサンプルコード

以下のサンプルコードは、画面内にキャラクター画像が2人表示されてだんだん近づき、重なってすれ違う、というものです。CharactorBaseという親クラスを、子クラス1、2がそれぞれ継承しています。
それぞれのキャラクターはgame.onload() 内でインスタンス化され、そのクラスはそれぞれ子クラス1、2です。
この時点ではまだ、2つのインスタンスは何も関係を持っていません。

enchant();

window.onload = function() {
    game = new Game(320, 320);
    game.preload("img/chara5.gif", "img/chara05_c.gif");
    game.onload = function(){
        chara1 = new Charactor1(50, 100, +2);
        chara2 = new Charactor2(250, 100, -2);
    }
    game.start();
}

/** キャラクターの親クラス */
var CharactorBase = enchant.Class.create(enchant.Sprite, {

    initialize: function(posX, posY, direction) {
        Sprite.call(this, 32, 32);
        this.image = game.assets['img/chara5.gif'];
        this.x = posX;
        this.y = posY;
        this.direction = direction;

        this.addEventListener('enterframe', function(){
            this.x += this.direction;
        });
        game.rootScene.addChild(this);
    }
});

/* 子クラス1 */
var Charactor1 = enchant.Class.create(CharactorBase, {
    initialize: function(posX, posY, direction) {
        CharactorBase.call(this, posX, posY, direction);
    }
});

/** 子クラス2 */
var Charactor2 = enchant.Class.create(CharactorBase, {
    initialize: function(posX, posY, direction) {
        CharactorBase.call(this, posX, posY, direction);
    }
});

接触判定を、各クラス内で定義する

ここから、2つのインスタンスが接触したら終了、という関係を持たせてみます。
子クラス1の定義を次のように書き換えます。

/* 子クラス1 */
var Charactor1 = enchant.Class.create(CharactorBase, {
    initialize: function(posX, posY, direction) {
        CharactorBase.call(this, posX, posY, direction);
        this.addEventListener('enterframe', function(){
            if (this.intersect(chara2)) {
                game.end();
            }
        });
    }
});

追加した EventListener内で、this.intersect()を使って衝突判定を行っています。
このクラス内で宣言したのではない、chara2という変数を使用して判定を行うことができています。

if (chara1.intersect(chara2)) {
    game.end();
}

このように、this を chara1 に書き換えても大丈夫。chara1もchara2もちゃんと見えます。
処理順だけ考えると、これを書いているのはCharactor1クラスのコンストラクタ内。コンストラクタが呼び出される時点ではchara1の初期化は済んでおらず、chara2なんてこの変数が使えるのが不思議でした。

変数のスコープ

さて、一方。

chara1、chara2の宣言部分を次のようにしてみます。

game.onload = function(){
    var chara1 = new Charactor1(50, 100, +2);
    var chara2 = new Charactor2(250, 100, -2);
}

変数宣言に、var を追加。
すると、2キャラとも画面の描画までは出来ますがまったく動かなくなりました。EventListenerの処理が出来ていないようです。
画面表示までは出来るということは、どうやらEventListener内の処理は、各イベントが発生して呼び出されるまでは一切呼ばれないのですね。クラス定義の中で、初期化されていないインスタンスを使っても大丈夫なことが納得できました。

調べたところ var を付けた変数はローカル変数、var を付けない変数はグローバル変数という扱いになるそうです。
私のJavascriptに関する理解は「変数宣言のときは var はつけてもつけなくても大丈夫、でも付けるほうが望ましい」ぐらいだったので、前回は付けていたためエラーになっていました。

ちなみにローカル変数である以上、同じ関数の中ならば見えることになります。

今回使ったサンプルでは window.onload 関数や game.onload 関数とクラス定義を宣言している関数をまったく別々に記述したので、前述のような結果になっていました。
しかしJavascriptではクラス定義をどこにでも書くことが出来ます。
ここから、クラス定義を game.onload 関数内に移動し、次のような構造とすることが可能。


enchant();

window.onload = function() {
    game = new Game(320, 320);
    game.preload("img/chara5.gif", "img/chara05_c.gif");
    game.onload = function(){

        /** キャラクターの親クラス */
        var CharactorBase = enchant.Class.create(enchant.Sprite, {
            // ...
        });

        /* 子クラス1 */
        var Charactor1 = enchant.Class.create(CharactorBase, {
            // ...
        });

        /** 子クラス2 */
        var Charactor2 = enchant.Class.create(CharactorBase, {
            // ...
        });

        var chara1 = new Charactor1(50, 100, +2);
        var chara2 = new Charactor2(250, 100, -2);
    }
    game.start();
}

これなら、変数宣言にvarを付けても動きました。
こっちの方が明示的に変数宣言できるし、お作法としてはいいのかな?


ということで、変数のスコープが原因で詰まっていました。
javascript独特の考え方などでだいぶ混乱しましたが、ここまでわかれば、基本的なクラスベースな実装は出来そうです。


Posted by ragi_d at 18:27│Comments(1)TrackBack(0)その他技術系 はてなブックマーク - enchant.js で、インスタンス間の連携をクラス内に記述する

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/ragi_d/65640494
この記事へのコメント
5
varでローカル扱いだったのですね・・・
キャラクラス内のgame.assetsだけ反応してくれなくてずっと困っていました。
ほかの人のコードとずっと見比べてもわからずネットをさまよっていたらここにたどり着きまして、コードを見直してみたらgameをnewするときにvar付けてました。
これで無事キャラ画像が表示されました!
Posted by 通りすがりの残念な人 at 2012年06月05日 00:28

コメントする

名前
URL
 
  絵文字