ActionScript 3.0で始めるオブジェクト指向スクリプティング

第24回 インスタンスの管理と配列の並べ替え

この記事を読むのに必要な時間:およそ 7 分

本題に戻って,EllipticMotionインスタンスの重ね順の処理を考えよう。インスタンスの仮想3次元の奥行きは,getIndexZ()メソッドで調べられた。したがって,配列 ⁠instances_array)に入ったインスタンスの順序を,インスタンスに対するgetIndexZ()メソッドの戻り値で並べ替える。そのための比較関数compare()の定義は,次のようになる。

function compare(a:EllipticMotion, b:EllipticMotion):Number {
  // 各インスタンスの仮想3次元の奥行きを調べる
  var nA:Number = a.getIndexZ();
  var nB:Number = b.getIndexZ();
  // 各インスタンスの奥行きに応じて並べ順を返す
  if (nA < nB) {
    return -1;
  } else if (nA > nB) {
    return 1;
  } else {
    return 0;
  }
}

仮想3次元の奥行きの順に配列(instances_array)内のEllipticMotionインスタンスを並べ替えても,まだ実際の表示上の重ね順には反映されない。 EllipticMotionインスタンスの表示リスト内の順序を,この配列内の新たな並べ順に合わせる必要がある。

表示リスト内におけるインスタンスのインデックスの位置を変えるのは,DisplayObjectContainer.setChildIndex()メソッドだ。つぎのシンタックスで,(DisplayObjectContainer)インスタンスの表示リストに含まれている子のDisplayObjectインスタンスを,指定したインデックスに移動する。

親インスタンス.setChildIndex(子インスタンス:DisplayObject, インデックス:int):void

ここでメインタイムラインのフレームアクションに,新たな関数 setOrder()を定義する。この関数は,まず前掲の比較関数compare()で配列instances_array内の EllipticMotionインスタンスを,仮想3次元の奥行きの順に並べ替える。つぎに,EllipticMotionインスタンスの表示リスト内の順序を,配列instances_arrayのエレメントの順序に合わせてDisplayObjectContainer.setChildIndex()メソッドにより設定している。

function setOrder():void {
  instances_array.sort(compare);   // 前掲比較関数で並べ替え
  var nLength:uint = instances_array.length;
  for (var i:int = 0; i<nLength; i++) {   // 並べ替えた配列内のインスタンスを順に取出し
    var _mc:EllipticMotion = instances_array[i];
    setChildIndex(_mc, i);   // 表示リスト内のインデックスを設定
  }
}

以上,2つの関数を追加したフレームアクションが,次のスクリプト2だ。なお,関数setOrder()の呼出しは,DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数rotate()の最後に加えている。

スクリプト2 インスタンスを仮想3次元の奥行きの順に並べ替える

// タイムライン: メイン
var myCenter:Point = new Point(stage.stageWidth / 2,stage.stageHeight / 2);
var myRadius:Point = new Point(100,50);
var nCount:uint = 6;
var nDegree:Number = 360 / nCount;
var instances_array:Array = new Array();
var deceleration:Number = 0.1;
for (var i:int = 0; i < nCount; i++) {
  var _mc:EllipticMotion = new EllipticMotion(nDegree * i,myCenter,myRadius);
  addChild(_mc);
  instances_array.push(_mc);
}
addEventListener(Event.ENTER_FRAME, rotate);
function rotate(EventObject:Event):void {
  var nSpeed:Number = (stage.mouseX - myCenter.x) * deceleration;
  var nLength:uint = instances_array.length;
  for (var i:int = 0; i < nLength; i++) {
    var _mc:EllipticMotion = instances_array[i];
    _mc.rotate(nSpeed);
  }
  setOrder();   // 追加: 関数呼出し
}
function setOrder():void {   // 追加定義
  instances_array.sort(compare);
  var nLength:uint = instances_array.length;
  for (var i:int = 0; i<nLength; i++) {
    var _mc:EllipticMotion = instances_array[i];
    setChildIndex(_mc, i);
  }
}
function compare(a:EllipticMotion, b:EllipticMotion):Number {   // 追加定義
  var nA:Number = a.getIndexZ();
  var nB:Number = b.getIndexZ();
  if (nA < nB) {
    return -1;
  } else if (nA < nB) {
    return 1;
  } else {
    return 0;
  }
}

このまま[ムービープレビュー]を確かめると, EllipticMotionクラスのgetIndexZ()が「アクセスできないメソッド」であるという[コンパイルエラー]が表示される図4⁠。これは,フレームアクションに定義した関数compare()からインスタンスのgetIndexZ()メソッドを呼出している,次の2行のステートメントに対するエラーだ。

function compare(a:EllipticMotion, b:EllipticMotion):Number {
  var nA:Number = a.getIndexZ();
  var nB:Number = b.getIndexZ();

図4 メソッドにアクセスできない旨を伝える[コンパイルエラー]

図4 メソッドにアクセスできない旨を伝える[コンパイルエラー]

これは前掲スクリプト2でEllipticMotionクラスのrotate()メソッドについて,そのアクセス制御の属性を修正したのと同じ理由だ。スクリプト2では,getIndexZ()メソッドにはprivate属性が指定されている。しかし,タイムラインのフレームアクションからメソッドを呼出すには,アクセス制御の属性としてつぎのようにpublicを指定しなければならない。

// private function getIndexZ(nMin:Number=-1, nMax:Number=1):Number {
  public function getIndexZ(nMin:Number=-1, nMax:Number=1):Number {
    var nIndexZ:Number = (nMax-nMin)*(sin+1)/2+nMin;
    return nIndexZ;
  }

スクリプト2に追加する修正はこの点のみなので, EllipticMotionクラスの定義全体を再掲することは控えよう。サンプルファイルをダウンロードして確かめてほしい。今度は[ムービープレビュー]がエラーなく行え,インスタンスの重ね順もつねに仮想3次元の奥行きに合わせて表示される図5⁠。

図5 仮想3次元の奥行きに応じてインスタンスの重ね順が設定される

図5 仮想3次元の奥行きに応じてインスタンスの重ね順が設定される

今回解説した次のサンプルファイルがダウンロードできます。

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書