AS3におけるroot参照

AS2はもとより、AS3でもrootを参照することはあまりないと思うけど、AS3でのルート参照を調べてみたら、かなり直感的ではないことがわかったのでレポートします。
いざというときに役に立つかも。

●そもそもFlashにおけるルートとはなんぞや

画面上に表示されるオブジェクトを「表示オブジェクト」とし、表示オブジェクトのコンポジット構造を「表示オブジェクトツリー」とすると、「ルート」とは「表示オブジェクトツリー」のルートノードである
という定義でいいと思う。多分。

問題は、AS2ではすべての表示オブジェクトは、一本の「表示オブジェクトツリー」で表現されていたが、(例外として、loadMovieNum()を使用した場合は、そこから新しく表示オブジェクトツリーが生成されていた。もうあんまり覚えてないけど。あと、MovieClip._lockrootとか。。使ってなかったけど。)AS3の場合は、どうもそう単純な話ではない様子。

●AS3におけるroot参照

たとえば、以下のような表示オブジェクトツリーがあるとする。(クリックで拡大します)
a image of display object tree
Stage直下にLoaderやDisplayObjectが存在するのに違和感を感じるかもしれないが、
Stage.addChild()が可能である以上、これは普通に起こりえる状況。
さて、それぞれのオブジェクトのrootプロパティはいったい何を指すでしょうか。

答えは ↓
一見するとかなり複雑に見える。(クリックで拡大します)
a image of pointing root

で、がんばって、一般化してみた。
あるオブジェクトのrootプロパティが何を指すかは、そのオブジェクトの親をたどっていき、

1・Loaderにぶちあたったら、そのLoaderに読み込まれたDisplayObjectがroot。
2・DocumentClassにぶちあたったら、それがroot。
3・Stageにぶちあたったら、それがroot。

言い方を変えると、
Stageから下におりていき、DocumentClassかLoaderに読み込まれたDisplayObjectにぶちあたったら
そのオブジェクトをrootとしてあたらしい表示オブジェクトツリーが開始される。

ちなみに、表示オブジェクトツリーを色分けしてみるとこんな感じ。
a image of pointing to root

最後に検証したコードと出力結果です。

package
{
    import flash.display.*;
    import flash.net.*;
    import flash.events.*;
    public class Main extends Sprite
    {
        private static  var cnt : int = 0;
        
        public function Main ()
        {
            if (stage)
            {
                //Test1
                test(this);
            }
        }

        
        
        
        public override function toString () : String
        {
            return (parent is Loader) ? "Loader.content" : "DocumentClass";
        }

        
        
        
        private function test (target : DisplayObjectContainer) : void
        {
            cnt ++;
            trace("¥n¥n/************************************");
            trace(" *" + cnt + "¥tTest about " + target + "'s root");
            trace(" ****************************/");
            var stageChildren : int = stage.numChildren;
            trace(" * now, Stage has " + stageChildren + "children");
            for (var i : int;i < stageChildren; i ++) trace("¥t¥t" + stage.getChildAt(i));
            
            //check parent
            trace(target + "'s parent is " + target.parent);
            
            //check root
            trace(target + "'s root is " + target.root);
            
            //check Stage's root
            trace("Stage's root is always Stage : " + (target.stage.root is Stage));
            
            if (cnt == 1)
            {
                //check DocumentClass'children
                var spr : Sprite = new Sprite();
                var spr2 : Sprite = new Sprite();
                spr.addChild(spr2);
                target.addChild(spr);
                trace("root of DocumentClass's child  is DocumentClass : " + (spr.root == target && spr2.root == target));
                
                var anortherChildOfStage : Sprite = new Sprite();
                var grandChildOfStage : Sprite = new Sprite();
                anortherChildOfStage.addChild(grandChildOfStage);
                target.stage.addChild(anortherChildOfStage);
                //Test2
                test(anortherChildOfStage);
            } else if (cnt == 2)
            {
                //Test3
                test(target.getChildAt(0) as DisplayObjectContainer);
            } else if (cnt == 3)
            {
                var loader : Loader = new Loader();
                loader.load(new URLRequest("root.swf"));
                loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadedLoader);
            }
            else if(cnt == 5)
            {
                var loader2 : Loader = new Loader();
                loader2.load(new URLRequest("root.swf"));
                loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadedLoader2);
            }
        }

        
        
        
        private function onLoadedLoader (event : Event) : void
        {
            var loader : Loader = LoaderInfo(event.target).loader;
            stage.addChild(loader);
            //Test4
            test(loader);
            //Test5
            test(loader.content as DisplayObjectContainer);
        }

        
        
        
        private function onLoadedLoader2 (event : Event) : void
        {
            var loader : Loader = LoaderInfo(event.target).loader;
            this.addChild(loader);
            //Test6
            test(loader);
            //Test7
            test(loader.content as DisplayObjectContainer);
        }
    }
}

//結果

/************************************
*1	Test about DocumentClass's root
****************************/
* now, Stage has 1children
DocumentClass
DocumentClass's parent is [object Stage]
DocumentClass's root is DocumentClass
Stage's root is always Stage : true
root of DocumentClass's child  is DocumentClass : true
/************************************
*2	Test about [object Sprite]'s root
****************************/
* now, Stage has 2children
DocumentClass
[object Sprite]
[object Sprite]'s parent is [object Stage]
[object Sprite]'s root is [object Stage]
Stage's root is always Stage : true
/************************************
*3	Test about [object Sprite]'s root
****************************/
* now, Stage has 2children
DocumentClass
[object Sprite]
[object Sprite]'s parent is [object Sprite]
[object Sprite]'s root is [object Stage]
Stage's root is always Stage : true
/************************************
*4	Test about [object Loader]'s root
****************************/
* now, Stage has 3children
DocumentClass
[object Sprite]
[object Loader]
[object Loader]'s parent is [object Stage]
[object Loader]'s root is [object Stage]
Stage's root is always Stage : true
/************************************
*5	Test about Loader.content's root
****************************/
* now, Stage has 3children
DocumentClass
[object Sprite]
[object Loader]
Loader.content's parent is [object Loader]
Loader.content's root is Loader.content
Stage's root is always Stage : true
/************************************
*6	Test about [object Loader]'s root
****************************/
* now, Stage has 3children
DocumentClass
[object Sprite]
[object Loader]
[object Loader]'s parent is DocumentClass
[object Loader]'s root is DocumentClass
Stage's root is always Stage : true
/************************************
*7	Test about Loader.content's root
****************************/
* now, Stage has 3children
DocumentClass
[object Sprite]
[object Loader]
Loader.content's parent is [object Loader]
Loader.content's root is Loader.content
Stage's root is always Stage : true

出力の1〜7の番号は、以下のオブジェクトに対応します。

●最後に

検証コード自体複雑になってしまって、もしかしたらまちがってるかもしれん。
あと、すべてのDisplayObjectについて検証したわけじゃないので、
Loaderみたいな特別なやつが他にもいるかもしれん。

ひとついえるのは、AS2の感覚でrootを使うと間違いなくはまる。
自分が何をしようとしているか、はっきりと確信を持っている時じゃなければ、
root参照は使わない方がいいんじゃないでしょうか。

カテゴリー: ActionScript3, AS3fromAS2 パーマリンク

AS3におけるroot参照 への2件のフィードバック

  1. うむるむ のコメント:

    AS3での this == root 判定

    コンテンツごとにswfを分けて作る時、外部swfの最初に書いたりする条件文。
    自分自身が root かどうかを判定するとき、AS2だとまさにそのままの

  2. ピンバック: rootはどこ!?ActionScript3.0でrootを参照 | ブクマ!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です