2
votes

I have this baffling problem with Flash AS3 that I have been attempting to solve for a long time. I have a notion that perhaps this is a bug with the flash player, but perhaps you can shed some insight.

I have a MovieClip in Flash that is a star for 10 frames, a circle for another 10, and then a square for another 10, after which it will gotoAndPlay(1), replaying the animation. This MovieClip extends an AS3 class I have called FlipClip.

FlipClip has a function in it called reverseClip. This function's purpose is to flip certain graphic children around an axis every time Flash launches the EXIT_FRAME event.

public function FlipClip()
    {
        //as soon as this is instantiated, add the eventListener
        addEventListener(Event.EXIT_FRAME,flipTheClip);
    }

    public function flipTheClip(e:Event)
    {

        trace("currentFrame = " + currentFrame);

        //for sake of simplicity, we will flip every child
        for (var i=0; i<numChildren; i++)
        {

            var targetClip = getChildAt(i);
            var axis = 10;

            //if the target child has not already been flipped...
            if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
            {

                //reverse the child's direction with scaleX and move based on the axis
                targetClip.scaleX *=  -1;
                var dist:Number = targetClip.x - axis;
                targetClip.x = axis - dist;

            }
        }
    }

The obvious outcome is that every time we exit a frame, all of the graphic elements are flipped horizontally around x=10, and every ten frames the shape of the MovieClip changes from a star, to a circle, to a square. Right?

Nope.

The MovieClip does successfully flip around that axis, but then a strange problem occurs. The animation stops. The MovieClip is stuck as an eternal star. And Flash doesn't even recognize that the animation has stopped, as we get this output over and over;

currentFrame = 1
currentFrame = 2
currentFrame = 3
currentFrame = 4
...
currentFrame = 30
currentFrame = 1

All the way up to 30, at which point it goes back to one. The clip is still playing, but somehow the graphic elements are not updating!

Is this a problem with the flash player? Is this a problem with the code? Any help is appreciated!

I've uploaded the files for the .fla and .as on dropbox. I'm still figuring out how to embed something like that, but for now I'm gonna hope this link works for you.

https://www.dropbox.com/sh/hcljutesblichpp/AABKQ4Kn8OTwfTaeh0I3nnOZa?dl=0

UPDATE:

If I convert every individual shape into a MovieClip within the parent MovieClip, it plays correctly. However, this is not very memory efficient or feasible with complex animations. Hopefully this bit of information can help you solve the problem.

2
How does it transform from shape to shape? Can you share your .fla? That would be easiest I think. Sometimes when you modify object through code, it can override timeline stuffs. Why are you using EXIT_FRAME instead of ENTER_FRAME? You really need to learn how to use the semicolon, it's important.BadFeelingAboutThis
urk HTML is not my strong point, and I'm not experience at all with sharing files online. I'll try, and If you still can't access it, tell me and I'll try a different approachtheseal53
The reason that I use EXIT_FRAME instead of ENTER_FRAME is that I've noticed problems with children being rendered before the function is applied, making them facing the wrong way when the display list does its thing. EXIT_FRAME seems to solve this problem.theseal53

2 Answers

2
votes

There are couple of thing which you need to take care.

  1. You don't need to flip element based on the numChildren as it always return 1 as on each frame you will get single children.
  2. you also don't need to do the check another condition Math.abs(targetClip.scaleX) / targetClip.scaleX != -1 to set the flip.
  3. And also you need to use ENTER_FRAME instead of EXIT_FRAME. ENTER_FRAME works for the current frame whereas EXIT_FRAME works for previous frame.

Use the below code.

package 
{

    import flash.display.MovieClip;
    import flash.events.*;
    import flash.utils.setTimeout;

    public class FlipClip extends MovieClip
    {

        var mInstance
        var prevX;

        public function FlipClip()
        {
            //as soon as this is instantiated, add the eventListener
            addEventListener(Event.ENTER_FRAME,flipTheClip);
             mInstance = this;
            //mInstance.visible  = false;
        }



        public function flipTheClip(e)
        {

            this.scaleX *=  -1;
            prevX = this.x;
            if(this.scaleX < 0)
                this.x = prevX + this.width
            else
                this.x = prevX - this.width
        }

    }

}

Paste above code in FlipClip.as file and change the frame rate to 1. You need to update the moviClip placement based on your requirement.

Hope above answer solve your problem.

1
votes

You need to remove listener for EXIT_FRAME before playing animation. Also you are Flipping your movieClip here but not adding any code for playing it.

Paste below code in your FlipClip.as file.

package 
{

    import flash.display.MovieClip;
    import flash.events.*;
    import flash.utils.setTimeout;

    public class FlipClip extends MovieClip
    {

        var mInstance

        public function FlipClip()
        {
            //as soon as this is instantiated, add the eventListener
            addEventListener(Event.EXIT_FRAME,flipTheClip);
             mInstance = this;
            mInstance.visible  = false;
        }

        private function playallAnimation()
        {
            this.gotoAndPlay(1);
        }

        public function flipTheClip(e)
        {
            removeEventListener(Event.EXIT_FRAME,flipTheClip);

            //for sake of simplicity, we will flip every child
            for (var i=0; i<numChildren; i++)
            {

                var targetClip = getChildAt(i);
                var axis = 10;

                //if the target child has not already been flipped...
                if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
                {
                    //reverse the child's direction with scaleX and move based on the axis
                    targetClip.scaleX *=  -1;
                    var dist:Number = targetClip.x - axis;
                    targetClip.x = axis - dist;

                }
            }
            setTimeout(function()
            {
                mInstance.visible  = true;
                playallAnimation();
            },200);
        }

    }

}

Hope this will work for you.