AS3のgotoAndStop()問題とEvent.RENDERの使い道
AS3でタイムラインでgotoAndStop()やgotoAndPlay()を呼んだ直後、ステージに配置した要素にアクセスできないのは有名な話ですが、この現象の解決策があるようです。
Enabling Access to Timeline Items in AS3 after gotoAndStop()をざっくり意訳してみました。
Waiting a frame (using a callLater or simply hooking into one ENTER_FRAME event broadcast) will not be long enough. But there is another event dispatched by Stage which might work, Event.RENDER.
[意訳]1フレームの生成を待つの(calLlater関数を使うか、単純にENTER_FRAMEイベントの配信に引っ掛ける)のに時間はかからないが、もうひとつ、Stageに割り当てられたEvent.RENDERという 使えるイベントがあります。
I think the event sequence goes something like this:
[意訳]イベントシーケンスは次のようになっていると思います。
- myTitleField is defined here
- gotoAndStop( “step2″ );
- myTextField is null here
- Event.ENTER_FRAME is dispatched
- myTitleField is still null here
- Any code written on the keyframe itself is executed
- stage’s Event.RENDER is dispatched
- myTitleField is defined again!
[意訳]
- myTitleFieldが定義されます
- gotoAndStop( “step2″ );
- ここではmyTextFieldがnullになります
- Event.ENTER_FRAMEが配信されます
- myTitleFieldはまだnullです
- キーフレーム上のコードが実行されます。
- ステージの Event.RENDER が配信されます
- myTitleField が再び現れます
So thanks to a tip from Senocular, the RENDER event looks like what we need. To force this event to fire, you must call stage.invalidate(), also the event is only dispatched to items on a DisplayList, and on top of that, it doesn’t go through a typical capture phase, the event is broadcast directly to the DisplayObject, but that shouldn’t matter here.
[意訳]SenocularのTipsに感謝します。RENDERイベントはまさにわれわれが必要としていたものだった。このイベントを発行させるためにstage.invalidate()を呼ぶ必要がありますが、またこのイベントはDisplayList上の要素と、その上の要素に対してのみ発行され、典型的なキャプチャフェーズは通らず直接DisplayObjectに配信されますが、注意することではありません。
Ok so a sample might now look like this:
[意訳]次のようにすれば大丈夫。
public var myTitleField: TextField; protected function onAddedToStage( event: Event ): void { myTitleField.text = "Step" + currentStep; // All good stage.addEventListener( Event.RENDER, onStageRender ); } protected function showNextStep(): void { gotoAndStop( "step" + currentStep ); stage.invalidate(); } protected function onStageRender( event: Event ): void { myTitleField.text = "Step" + currentStep; // myTitleField is null! }
stage.invalidate()を呼ぶことで次のRENDERイベントをひろうことができます。
RENDERイベントって何に使うの?っていう話もありましたが、要するに表示する直前に表示要素をなにかすることで描画パフォーマンスをかけずに処理する場面があるということみたいですね。(個人的にはあまりなさそうですが)
ただ、ADDED_TO_STAGEとRENDERイベントについて、FlashPlayerにバグがあるので注意とのことです。
Note: It’s important to remember that there are bugs related to both Event.ADDED_TO_STAGE and Event.RENDER (with wmode). So best be sure your viewers are using Flash Player 9.0.115.0 or greater to avoid a world of pain
[意訳]補足:忘れてはならない重要なことは、Event.ADDED_TO_SATGEとEvent.RENDER(wmode利用時)の両方ともに既知のバグがあることです。したがって、残念な思いをしないようあなたの閲覧者がFlashPlayer9.0.115.0以上を利用していることをよく確認してください。