AS3 8BitBoy in Flash 9 IDE Eclipse undelete option
août 05

Here is a little trick that may help you to target items on scene right after a gotoAndStop/gotoAndPlay

Here is an annoying thing i faced today :

I used to program clips or buttons with several labels, and populate items at each label content when needed.

But in AS3, there is no way to do such things :

button_mc.gotoAndPlay("over");

button_mc.tf_over.text = "rollover text";

does not work at all.

I found a trick that used the Event.RENDER event which occurs after an enterframe : http://www.kirupa.com/forum/showthread.php?p=1914687

But i did not wanted to use an enterframe, and i found a second trick on Senocular site which uses the stage.invalidate()

The invalidate method forces the current displayObject to render itself immediately.

So to sum up the trick, we have to :

  • go the new frame using gotoAndStop/gotoAndPlay
  • add a listener on stage with Event.RENDER event
  • create a function that will populate the new frame

So here is an example where a button needs to go to the "over" frame and fill a text which exists on this frame :


// set a clip as a button
button_mc.buttonMode = true;

// add a mouse rollover listener
button_mc.addEventListener(MouseEvent.MOUSE_OVER, onOver);

// let's go for the trick
function onOver(evt:MouseEvent):void{
   // go to the new frame
   button_mc.gotoAndStop("on");

   // add a new listener on the stage to get the next render event
   stage.addEventListener( Event.RENDER, onButtonRollOver, false, 0, true );

   // force the current displayObject to trigger the Render event
   stage.invalidate();
}

// populate the rollOver frame
function onButtonRollOver(evt:Event):void{
   trace("render rollover");
   button_mc.tf_on.text = "RollOver text";
   // important : remove the listener
   stage.removeEventListener( Event.RENDER, onButtonRollOver);
}

I was quite happy to find this trick, but unfortunately there seems to be a deeper problem with the RENDER event : I managed my button with 2 listeners like above (one for rollOver, and another for rollOut).

All seems to be ok, but when I drag the mouse over and out the button quickly, the RENDER is triggered while the targeted textfield is not yet available.

SO, use this trick in your production if you don't intend to move the playhead of the displayObject too quickly. Or else, just wait for another trick....

4 Responses to “AS3 gotoAndStop & gotoAndPlay issue”

  1. ekameleon Says:

    Hello :)

    I prefere use my personnal button class FrameLabelButton :
    http://www.ekameleon.net/vegas/d...

    More easy, you can add the "up", "down", "disabled", "over", "release", "over_selected", "out_selected", …. frames in your movieclip and the class work for you ;)

    EKA+ :)

  2. Arthy Says:

    EKA always ahead… :)

    I will need some time to get around you great framework !

    Finally i have chosen an old as2 way to solve this : create a Waiter class.

    So i can call the function :

    doNext(cb:Function, scope:*, nbFrames:int = 1)

    – cb : the callback function called after waiting
    – scope : the class/object where the function is
    – nbFrames : number of frames to wait

    Here is the class code :

    ————————————————
    package net.lecrabe.tools.timer {
    import flash.events.TimerEvent;
    import flash.utils.Timer;

    /**
    * @author arthy / http://www.lecrabe.net
    */
    public class Waiter {

    private static var _callback:Function;
    private static var _scope:*;
    private static var _myTimer : Timer;

    private static var _stageFPS : int = 1;

    public function Waiter() {
    }

    // Init Waiter class framerate first (with stage.frameRate)
    public static function initFPS(fps:int){
    _stageFPS = fps;
    }

    // call main function to wait for nb frames until executing the callback function
    public static function doNext(cb:Function, scope:*, nbFrames:int = 1) : void {
    if (_stageFPS==0) trace("WARNING : Waiter fps=1, please call Waiter.init(fps);");

    _callback = cb;
    _scope = scope;

    var wait:int = int(1000/_stageFPS)*nbFrames;

    _myTimer = new Timer(wait, 1);
    _myTimer.addEventListener(TimerEvent.TIMER, timerHandler, false, 0, true);
    _myTimer.start();
    }

    // executes callback function
    private static function timerHandler(event:TimerEvent):void {
    _myTimer.removeEventListener(TimerEvent.TIMER, timerHandler);
    _callback.apply(_scope);
    }

    }
    }

    ————————————————

    And finally i just have to write this :

    import net.lecrabe.tools.timer.Waiter;

    // need to set the right fps to the class
    Waiter.init(stage.frameRate);

    // move to the new label
    gotoAndStop("myNewLabel");

    // wait for 1 frame
    Waiter.doNext(onPopulateMyClip, this);

    function onPopulateMyClip():void{
    // timeline playhead is stopped, i can populate the movieclip
    }

    I know there may be others way, but finally this one is quite simple i think.

  3. Thomas Says:

    ils sont mignons à parler anglais

    kiss & love

  4. Arthy Says:

    By the way, this problem no longer exists on Flash Player 10 (even 9 as far as i remember)

Leave a Reply

IMPORTANT! To be able to proceed, you need to solve the following simple math (so we know that you are a human) :-)

What is 10 + 7 ?
Please leave these two fields as-is: