メインタイムライン・ステージ・ルート

ところで

 Flex3も正式リリースされる今日この頃。Flash(ActionScript3.0)リファレンス概要というヤツを、じみーに作ってます。
 ずいぶん頭の中が整理できましたが、個々のオブジェクトの使い方や大きな概念は、今イチ分かってません。 

メインタイムライン

 前回はメインタイムラインにドキュメントクラスを追加して、グローバルで使える関数・変数の定義方法が分かった訳です。
 んじゃ、ドキュメントクラスを追加する前のドキュメントクラス(つまりデフォルト)はどうなっているか、ってのが気になったので、メインタイムラインに次のコードを書いて確かめてみる。

trace( this );

 んで、返ってきた値は次のような文字列。要するにデフォルトではMainTimelineというオブジェクトのインスタンスが割り当てられているようだ。stop()とかplay()を受け付けるのでMovieClipを拡張(extends)したクラスではあるらしい。

[object MainTimeline]

 プログラマ気分 | 【AS3.0】_flaパッケージ(Flashのみ)によると、MainTimelineというやつは「ファイル名_fla」というパッケージの中に有るそうな。だからなんだという感じだけど、多少はMainTimelineクラスが何ものかということを理解する助けになるかな…ならんか?
 更に、flash.utilsパッケージにはdescribeType()メソッドという、オブジェクトの構造をXML化してくれる、調査に便利なメソッドが用意してある。他にもgetDefinitionByName ()とかflash.utilsパッケージには便利そうなメソッドが列んでいる。
 てなわけで、describeType()でMainTimelineを調べてみる。

trace( describeType( this ) );

 作った直後のflaでテストした結果は次の通り。何を拡張(extendsClass)してどんなインタフェース(implementsInterface)があって、どういうメソッド(method)とプロパティ(ここではaccessor)が実装されているかが、だーっと出てくる。
 確かに最初のところでname="_fla::MainTimeline"とあって、_flaというパッケージの中身だと分かるし、MovieClipを拡張しているということも分かる。

<type name="_fla::MainTimeline" base="flash.display::MovieClip" isDynamic="true" isFinal="false" isStatic="false">
  <extendsClass type="flash.display::MovieClip"/>
 …以下続く

 前回のようにカスタマイズしたドキュメントクラスを割り当てると、メインタイムラインはMainTimelineからそのクラス名に変わる。
 例えば、前回のMainクラスの場合のtrace( this );は次のようになる。

[object Main]

 特に名前を変える必要性もない気がするので、これからはとりあえずドキュメントクラス名はデフォルトと同じ「MainTimeLine」で行くことにする。

さてrootですが

 AS2までは、_rootというグローバルプロパティだったそーなんですが。
 AS3ではrootという名前のDisplayObjectプロパティになってます。
 rootはDisplayObjectなので、MovieClipと思って使おうとすると色々と受け付けてくれないメソッドやプロパティが満載です。また動的に追加した関数にもアクセスできなかったりします。
 FN0707001 - rootプロパティでメインタイムラインの関数にアクセスできない - Flash : テクニカルノートによると、そういう場合は、MovieClipへキャストすればOKということらしい。

 Σc ' _' )  < …メンドクセ。

 なんで、こういう面倒くさいことになっているかというと、rootが指す場所がメインタイムラインだとは限らない、からのようです。
 1.5 rootとstage (Flash ActionScript3.0入門ノート)によると、次のような場合があるそうです。

1.表示オブジェクトがStageに直接追加されている。→ Stageオブジェクト
2.SWFを読み込んでいる。→ 読み込んだSWFのメインのタイムライン
3.読み込んだ外部イメージ(content.root)。→ Bitmapオブジェクト
4.ドキュメントクラスを指定している。→ ドキュメントクラス
5.表示リストに追加されていない表示オブジェクト。→ null

 理由は分かるけど面倒は面倒なので、ドキュメントオブジェクトにrootObjとか名前つけてプロパティを用意しておけば、以前と近い感覚でルートを使えるように…なるのか?
 しばらく試行錯誤…どうもできるっぽい。static publicでなんぞ変数を作っておけば良さそうだ。関数でもいいんだろうけど、ほぼ const みたいなもんだから毎回メソッドを実行する意味もなさげ。
 メインタイムラインは事実上singlton(プログラム全体でインスタンスが一つしかないオブジェクト)なんで、コンストラクタにstaticな変数の初期化処理を書いても大丈夫…なはず。
 できたドキュメントオブジェクトは次のような感じ。

package {
    import flash.display.MovieClip;
    public class MainTimeline extends MovieClip {
        static public var rootMC:MovieClip;
        public var rootObj:MovieClip;
        function MainTimeline() {
            rootMC = root as MovieClip;
            stop();
        }
    }
}

 あとは、ドキュメントオブジェクトだけあって、importすることもなくいきなり次のように使える。

MainTimeline.rootMC.nextFrame();

 とはいえ_root.nextFrame()と書け(ちゃっ)てた、AS2に比べると冗長だねぇ。
 MainTimelineとか書くの止めて、"_"とかにしちゃったら短くて良くね?とか思わんでもないが、prototype.jsの$みたいで、カッコいいようなダサイような感じだ。

でStageです

 DisplayObjectのプロパティにはrootの他にAS3.0にはstageなんてもんがある。
 また、メインタイムラインで、trace( parent );を書くと、[object Stage]と出る。
 どうも、MainTimelineの上の階層のオブジェクトのようだ。上のFlash ActionScript3.0入門ノートの解説によれば場合によってはrootになることもあるそうな。
 FlashCS3で作っていると感覚的にはMainTimelineが土台という感じが強いが、FlexだとMainTimelineが無いのでStageが土台という感覚になる気がする。
 Flash CS3でもここにオブジェクトを追加(addChild)できる訳なんだが、そうなるともうFlashオーサリング環境を使う意味は無いしなぁ。

  オーサリング環境でもステージと呼んでいる部分が、このstageらしい。
 rootと違って、stageプロパティで返ってくる値のクラスはStageなので、特に型変換(cast)を行わなくてもStageオブジェクトとして使える。

 以前だとPlayerにfscommand()送ってたようなフルスクリーンモードも、ここでdisplayStateを変えて設定できる。
 htmlの設定でallowFullScreenをtrueにしとかなきゃいけないとか、ユーザのアクションがトリガになっていないとフルスクリーンにできないとかの制限がある。
 セキュリティって面倒やのう。もっと上手い方法は無いものか。

import flash.display.StageDisplayState;
 
_btn.addEventListener( MouseEvent.MOUSE_CLICK, onClick );
function onClick( e:Event ):void {
	stage.displayState = StageDisplayState.FULL_SCREEN;
}

 クリックイベントの扱いが変わったのと、rootやparentの仕様が変わったのが、ActionScript3.0になって戸惑う部分の二大巨頭ではなかろうか。
 理解するまで、えらく時間かかった。

 今日はここまで。


2008-03-08