actionscript-3enterframeevent

A loop in enterframe?


I'm animating a bunch of words in AS3. Because I'm going to be using this on a mobile device, I want to use bitmaps rather than Sprites. So I've created WordObjects, which have a .bitmap property that I can access.

I have the following code, which fires on the click event and loops through an array inside an enterframe event. This is probably a bad idea, but I'm not sure how to do it better. (What is surprising is that it runs just fine in Flashbuilder, but slows to a crawl in Flash CS5.)

Is there some better way to do this? I just want an efficient way to animate the array of bitmaps.

    private function clickhandler (e:MouseEvent){

        this.addEventListener(Event.ENTER_FRAME, blowemup);
    }
    private function blowemup(e:Event){
        var newPosition:Number;
        for(var i:int=0; i<arrWordObjects.length; i++)
        {
            newPosition = updatePosition(arrWordObjects[i].bitmap);
            arrWordObjects[i].bitmap.x += newPosition;
            arrWordObjects[i].bitmap.y += getRandomNumber();

        }
    }

Solution

  • Something that will make a huge difference is using for each(Object in Array) rather than the standard for loop.

    private function blowemup(e:Event):void
    {
        var newPosition:Number;
    
        var i:ArrWordsObjectClass; // <-- don't know what the class for this is, just replace
        for each(i in arrWordObjects)
        {
            newPosition = updatePosition(i.bitmap);
            i.bitmap.x += newPosition;
            i.bitmap.y += getRandomNumber();
        }
    }
    

    A for each loop is typed, meaning a lot of time is saved where normally it'd be trying to work out what arrWordObjects[i] is every iteration.

    Also, side note: using one ENTER_FRAME driven function and looping through everything in your application that you want to handle each frame is much more efficient than applying hundreds of listeners for objects.

    I normally create a handler class that contains the ENTER_FRAME and an array storing my objects, like so:

    package
    {
        import flash.events.Event;
        import flash.display.Sprite;
    
        public class Handler extends Sprite
        {
            // vars
            public var elements:Array = [];
    
            /**
             * Constructor
             */
            public function Handler()
            {
                addEventListener(Event.ENTER_FRAME, _handle);
            }
    
            /**
             * Called on each dispatch of Event.ENTER_FRAME
             */
            private function _handle(e:Event):void
            {
                var i:Element;
                for each(i in elements)
                {
                    i.step();
                }
            }
        }
    }
    

    Then I create a base class for all the objects that I want to handle, containing the step() function called above.

    package
    {
        import flash.display.DisplayObject;
    
        public class Element extends Object
        {
            // vars
            public var skin:DisplayObject;
    
            /**
             * Called on each dispatch of Event.ENTER_FRAME at Handler
             */
            public function step():void
            {
                // override me
            }
        }
    }
    

    Now just extend Element with your objects:

    package
    {
        import flash.display.Sprite;
    
        public class MyThing extends Element
        {
            /**
             * Constructor
             */
            public function MyThing()
            {
                skin = new Sprite();
    
                skin.graphics.beginFill(0);
                skin.graphics.drawCircle(0,0,40);
                skin.graphics.endFill();
            }
    
            /**
             * Override step
             */
            override public function step():void
            {
                skin.x += 4;
            }
        }
    }
    

    And get it all going!:

    var handler:Handler = new Handler();
    
    var m:MyThing;
    var i:uint = 0;
    for(i; i<10; i++)
    {
        m = new MyThing();
        m.y = Math.random()*stage.stageHeight;
    
        handler.elements.push(m);
        addChild(m.skin);
    }