サイトトップ

Director Flash 書籍 業務内容 プロフィール

Adobe Flash非公式テクニカルノート

同階層のインスタンスを参照する

ID: FN0901003 Product: Flash CS3 and above Platform: All Version: 9 and above/ActionScript 3.0

オーサリング時にタイムラインに配置されたインスタンスを、ActionScript 3.0で互いに参照する場合について説明します。メインタイムラインに3つのMovieClipインスタンスmy1_mc、test_mc、my2_mcを、この重ね順に配置します。3つのインスタンスは、わかりやすいようにそれぞれレイヤーに分け、レイヤーにはインスタンス名を設定しました(図001)。

図001■メインタイムラインに3つのインスタンスをレイヤーに分けて配置


1. メインタイムラインから子のインスタンスを参照する
まず、メインタイムラインのフレームアクションで、子のMovieClipインスタンスを参照してみます。ActionScript 3.0では、子のインスタンスは親インスタンスの表示リストに加えられます。表示リスト内のインスタンスの数はDisplayObjectContainer.numChildrenプロパティで調べられ、DisplayObjectContainer.getChildAt()メソッドにインデックスを指定してインスタンスが取出せます。

以下のスクリプト001をメインタイムラインのフレームアクションとして記述すると、配置された3つのMovieClipインスタンスの情報が[出力]パネルに表示されます。なお、DisplayObjectContainer.getChildIndex()メソッドは、指定したインスタンスの表示リスト内におけるインデックスを返します[*1]

スクリプト001■メインタイムラインから子のMovieClipインスタンスをforループで参照する

// ActionScript 3.0
// メインタイムライン
trace(this);
var nChildren:uint = numChildren;
for (var i:uint = 0; i<nChildren; i++) {
  var _mc:DisplayObject = getChildAt(i);
  trace(i, _mc, _mc.name, this.getChildIndex(_mc));
}

[ムービープレビュー]を確かめると、3つのMovieClipインスタンスの名前やインデックス番号が[出力]パネルに表示されます(図002)。インデックス番号は0から始まり、重ね順(レイヤー)が上になるほど値は大きくなります。

図002■3つのインスタンスの情報が[出力]される

[*1] 上記スクリプト001では、DisplayObjectContainer.getChildIndex()メソッドは、DisplayObjectContainer.getChildAt()メソッドに渡したインデックス(i)と同じ値を返します。この値は、念のため[出力]に加えています。


2. 子のインスタンスから同階層のインスタンスを参照する
つぎは、子のインスタンスから、同階層の他のインスタンスを参照します。DisplayObject.parentプロパティで親インスタンスが取得できますので、あとは前述「1. メインタイムラインから子のインスタンスを参照する」と同じ要領で、メインタイムラインに配置された3つのインスタンスが参照できるはずです。以下のスクリプト002を、MovieClipインスタンスtest_mcの第1フレームアクションとして記述します。

スクリプト002■MovieClip内から同階層のインスタンスを参照する

// ActionScript 3.0
// MovieClip: test_mc
trace(this.name);
var nChildren:int = parent.numChildren;
for (var i:int = 0; i<nChildren; i++) {
  var _mc:DisplayObject = parent.getChildAt(i);
  trace(i, _mc, _mc.name, parent.getChildIndex(_mc));
}

前記スクリプト001も残しておくと、まずメインタイムラインのフレームアクションが先に実行され、そのあとMovieClipのフレームアクション(スクリプト002)が処理されることになります。[出力]されるインスタンスの情報は、どちらのスクリプトも同じになります(図003)。

図003■メインタイムラインとMovieClipのフレームアクションから同じ内容の[出力]が得られる


3. MovieClipシンボルに設定したクラスから同階層のインスタンスを参照する
今度は、ひとつのMovieClip(test_mc)のシンボルにクラスMyClassを設定します(図004)。処理内容は、前記スクリプト002と同じく、同階層のインスタンスを参照するというものです。クラスのコンストラクタメソッドから実行します。

図004■MovieClipシンボルにクラスを設定

クラスMyClassの定義は、以下のスクリプト003のとおりです。コンストラクタメソッドにおける処理は、基本的に前記スクリプト002と変わりません。ただし、trace()関数で各インスタンスの情報を[出力]する前に、それがDisplayObject(またはそのサブクラス)のインスタンスであることを確かめ、そうでない場合には[出力]する項目を減らしました。その理由は、[ムービープレビュー]で実際に[出力]内容を見るとわかります(図005)。

スクリプト003■クラスMyClassのコンストラクタから同階層のインスタンスを[出力]する

// ActionScript 3.0クラス定義: MyClass.as
package {
  import flash.display.DisplayObject;
  import flash.display.MovieClip;
  import flash.events.Event;
  public class MyClass extends MovieClip {
    public function MyClass() {
      trace(this);
      var nChildren:int = parent.numChildren;
      for (var i:int = 0; i<nChildren; i++) {
        var _mc:DisplayObject = parent.getChildAt(i);
        if (_mc is DisplayObject) {
          trace(i, _mc, _mc.name, parent.getChildIndex(_mc));
        } else {
          trace(i, _mc);
        }
      }
    }
  }
}

コンストラクタメソッドから参照すると、親インスタンスの表示リスト内のインデックス2がnullとして返されています。nullの参照に対してプロパティにアクセスしようとしたり、あるいはDisplayObjectContainer.getChildIndex()メソッドに引数としてnullを渡すと、ランタイムエラーになります。そのため、上記スクリプト003では、表示リストから取出した参照が、DisplayObjectインスタンスであることを確かめたのです。

図005■クラスのコンストラクタから参照すると前面のインスタンスはnullになる

MovieClipシンボルに設定したクラスのコンストラクタメソッドは、メインタイムラインの第1フレームアクションよりも先に呼出されます(上図005参照)。そして、コンストラクタはインスタンスを初期化します。その呼出しの順序は、表示リスト内のインデックス0から順に値の大きいインスタンス、つまり重ね順の背面から前面になります。したがって、コンストラクタが呼出されたとき、インデッスクの大きいインスタンスはまだ初期化されていません。そのため、参照を取得しても値がnullになってしまうのです[*2]

よって、MovieClipシンボルに設定したクラスから同じ階層のインスタンスを参照するには、その実行を少し遅らせる必要があります。具体的には、DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)にリスナー関数を登録して、その関数からそれらのインスタンスにアクセスすればよいでしょう(スクリプト004)。

スクリプト004■DisplayObject.enterFrameに登録したクラスのリスナー関数から処理を行う

// ActionScript 3.0クラス定義: MyClass.as
package {
  import flash.display.DisplayObject;
  import flash.display.MovieClip;
  import flash.events.Event;
  public class MyClass extends MovieClip {
    public function MyClass() {
      addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
    private function onEnterFrame(eventObject:Event):void {
      trace(this);
      var nChildren:int = parent.numChildren;
      for (var i:int = 0; i<nChildren; i++) {
        var _mc:DisplayObject = parent.getChildAt(i);
        if (_mc is DisplayObject) {
          trace(i, _mc, _mc.name, parent.getChildIndex(_mc));
        }
      }
      removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
  }
}

DisplayObject.enterFrameイベントに登録されたリスナー関数はタイムラインの第1フレームアクションの後に呼出されますので、表示リスト内のインデックスにかかわらず同階層のインスタンスを参照することができます(図005)。

図005■DisplayObject.enterFrameに登録したクラスのリスナー関数から同階層のインスタンスを参照

[*2] もっとも、スクリプト003の[出力](上図005)からは、初期化前のインスタンスもDisplayObjectContainer.numChildrenの数には含まれていることがわかります。


作成者: 野中文雄
作成日: 2009年1月14日


Copyright © 2001-2009 Fumio Nonaka.  All rights reserved.