サイトトップ

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

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

タイムラインに置いたMovieClipからフレーム移動するとrootやstageが参照できない

ID: FN1003002 Product: Flash Platform: All Version: CS4/ActionScript 3.0

問題
Flash Player 10で報告された問題です。予めタイムラインに置いたMovieClipインスタンスからメインタイムラインのフレームを移動すると、DisplayObject.rootDisplayObject.stageプロパティを参照できないことがあります。

たとえば、メインタイムラインに2フレームをつくり、その第1フレームのみにMovieClipインスタンスを置きます(図001)。MovieClipインスタンスには、とくにビジュアルエレメントは要りません。

図001■全2フレームのメインタイムライン第1フレームにMovieClipインスタンスを置く
図001左図 図001右図

MovieClipシンボルの第1フレームに、以下のスクリプト001を記述します(図002)。DisplayObject.enterFrameイベント(定数Event.ENTER_FRAME)のリスナー関数(xTest())から、メインタイムラインのつぎのフレームに移動します。DisplayObject.rootプロパティはDisplayObjectで型指定されていますので、MovieClipクラスのプロパティやメソッドにアクセスするときはMovieClipでキャストすべきことにご注意ください(「rootプロパティでメインタイムラインの関数にアクセスできない」の「対処法」[2]「キャスト」参照)。

スクリプト001■MovieClipインスタンスからメインタイムラインのフレームを移動する

// フレームアクション
MovieClip(root).stop();
root.addEventListener(Event.ENTER_FRAME, xTest);
function xTest(eventObject:Event):void {
  MovieClip(root).nextFrame();
  root.removeEventListener(Event.ENTER_FRAME, xTest);
}

図002■MovieClipシンボルに第1フレームアクションを記述
図002

[ムービープレビュー]を試すと、[出力]パネルにつぎのようなランタイムエラーが表示されます。

TypeError: Error #1009: null のオブジェクト参照のプロパティまたはメソッドにアクセスすることはできません。

原因
[ヘルプ]の[DisplayObject]クラスで「rootプロパティ」の項を見ると、つぎのような説明があります。

表示リストに追加されていない表示オブジェクトの場合、root プロパティには、null が設定されます。

インスタンスの存在していないフレームに移動すると、そのインスタンスは親の表示リストから削除されます。その結果、上記の説明のようにDisplayObject.rootプロパティの参照がnullになっているものと考えられます。

DisplayObject.stageプロパティにもつぎのような記述がありますので、その参照については同じ注意が必要です。

表示オブジェクトが表示リストに追加されていない場合、stage プロパティは null に設定されます。

対処法
処理の流れをできるだけ変えたくないという場合には、DisplayObject.rootプロパティへの参照を予め変数にとっておくことが考えられます(スクリプト002)[*1]

スクリプト002■予めDisplayObject.rootプロパティの参照を変数にもつ

// フレームアクション
var myRoot:MovieClip = MovieClip(root);
myRoot.stop();
myRoot.addEventListener(Event.ENTER_FRAME, xTest);
function xTest(eventObject:Event):void {
  trace(root, stage, myRoot.numChildren);   // テスト用
  myRoot.nextFrame();
  trace(root, stage, myRoot.numChildren);   // テスト用
  myRoot.removeEventListener(Event.ENTER_FRAME, xTest);
}

[ムービープレビュー]を試すと、エラーは生じません。また、テスト用にtrace()関数を加えていますので、つぎのような[出力]が示されます。フレームの移動によりDisplayObject.rootDisplayObject.stageプロパティがnullになり、親インスタンスの表示リストから削除されていることが確かめられます。

[object MovieClip] [object Stage] 1
null null 0

もっとも、自身の存在しないフレームに移動してスクリプトを実行し続けることには不安があります。そのときインスタンスからの参照がどのように変わるか明らかではないからです。実際、前掲スクリプト001は、Flash Player 9で書出すとエラーが生じないようです。インスタンスの表示リストから削除されるタイミングが変わったものと推測されます[*2]。そのタイミングはドキュメント化されている訳ではありませんので、仕様変更とみなされる余地が大きいでしょう。

そうすると、自身の存在しないフレームへの移動は、できるかぎりスクリプトの最後に行うことが安心です(スクリプト003)。

スクリプト003■親タイムラインのフレーム移動をスクリプトの最後に行う

// フレームアクション
var myRoot:MovieClip = MovieClip(root);
myRoot.stop();
myRoot.addEventListener(Event.ENTER_FRAME, xTest);
function xTest(eventObject:Event):void {
  myRoot.removeEventListener(Event.ENTER_FRAME, xTest);
  myRoot.nextFrame();   // 最後に親タイムラインのフレームを移動
}

もちろん、自身の存在しないフレームへの移動が原因ですので、移動先フレームまでインスタンスを継続して残すという対処法もあります。ただ、この問題を解消するためにタイムラインをいじるというのは、大げさでしょう。

[*1] 同じプロパティに対してキャストを何度も行う場合には、予め適切に型指定した変数に納めておくことは、最適化の観点からも意味があります(「ActionScript 3.0におけるパフォーマンス向上のヒント」02「型指定した変数を活用する」参照)。

[*2] 正確には、スクリプト002をFlash Player 9で書出すと、2行目の[出力]はつぎのようになります。

[object MovieClip] [object Stage] 0

つまり、親インスタンスの表示リストからは削除されているものの、DisplayObject.rootDisplayObject.stageプロパティの参照は残っているということです。すると、Flash Player 10の動きの方が整合性はあると考えられます(そのため仕様が変更されたのかもしれません)。


作成者: 野中文雄
作成日: 2010年3月12日


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