kag.fore/back.layersへのリファレンス

相変わらず吉里吉里のはまりどころについて書きます。

KAGを改造してゲームを作っているとしましょう。すると、扱うレイヤは自然とkag.fore.layers[FOO]だとかkag.back.layers[BAR]とかそんな感じになります。

さて例えば、ゲームのコンフィグ画面などで汎用的に使えるButtonクラスやPanelクラスを設計して、どのレイヤに対しても汎用的に使えるように、メンバとして何らかのレイヤへのリファレンスを持たせるとしましょう。具体的には次のようになります。

class Panel{
  var layer;

  function Panel(layer){
    this.layer = layer;
  }
}

var config = new Panel(kag.fore.layers[2]);

これは常識的なコードに思えます。少なくとも自分には、常識的なコードに思えます。ところがこのコードは、ゲーム中でトランジション、具体的にはkag.fore.base.beginTransionなどの処理が起こると使い物になりません。

それは何故かというと、トランジションの前後でkag.fore.layers[2]とkag.back.layers[2]の指し示すアドレスが交換されるからです。kag.fore.〜というのは常に表面を表すオブジェクトです。トランジションによって表レイヤと裏レイヤは逆転し、それまで裏レイヤだったものが表レイヤになります。それまで裏レイヤだった「オブジェクト」が表レイヤになっても、kag.back.〜は相変わらず名前のとおり裏レイヤを指し、同様にkag.fore.〜は表レイヤを指すように、それらの指すオブジェクトが交換されます。

つまり、トランジションが起こると、それまで表のレイヤ(kag.fore.layers[2])を指していたPanelクラスのメンバlayerは、裏のレイヤ(kag.back.layers[2])を指すことになるのです。したがって、このPanelクラスのレイヤも裏表を交換してやらなければなりません。具体的には、GraphicLayerのbeginTransition関数に、次のようなswapメソッドをフックします。

class Panel{
  var layer, backlayer;

  function Panel(layer, backlayer){
    this.layer = layer;
    this.backlayer = backlayer;
  }

  function swap(){
    var tmplayer = layer;
    layer = backlayer;
    backlayer = tmplayer;
  }
}

var config = new Panel(kag.fore.layers[2], kag.back.layers[2]);

GraphicLayerを書き換えるのが億劫ならば、レイヤへの参照をメンバとするのではなく、kag.fore.layers[2]を返す関数をPanelクラスに登録して遅延評価をするのが良いでしょう。

class Panel{
  var getLayer;

  function Panel(getLayer){
    this.getLayer = getLayer;
  }

  function show(){
    getLayer().loadImages(%[storage:'foo.png']);
  }
}

var config = new Panel(function(){return kag.fore.layers[2];});