Search code examples
performanceactionscript-3frame-rate

AS3: FPS drops down significantly because of innocent mouse moves


I have ~10000 objects in my game and exactly 60 (maximum) FPS when mouse isn't moved. But just when you start moving mouse in circles FPS tries to reach 30 averaging at 45. When you stop mouse it's INSTANTLY 60 (as so program lost it's heartbeat). SWF is run standalone - without any browsers.

I removed any MouseEvent.MOUSE_MOVE listeners and made mouseEnabled=false and mouseChildren=false for the main class.

I increased my FPS one-by-one from 12 to 60 - I gave name to each frame I born and it's really painful watching how 15 of them die just because of nothing...

Sample code:

public class Main extends Sprite
{
    private var _periods : int = 0;

    /** Idling FPS is 23. Move mouse to drop FPS to 21.*/
    public function Main() : void
    {
        //true if need to drop FPS to 18 instead of 21 moving mouse:
        const readyToKill2MoreFrames : Boolean = true;
        if ( readyToKill2MoreFrames )
        {
            var ellipse : Sprite = new Sprite;
            ellipse.graphics.beginFill( 0x00FF00 );
            ellipse.graphics.drawEllipse( 300, 300, 400, 200 );
            ellipse.graphics.endFill();
            addChild( ellipse );

            //uncomment to fall only to 21 instead of 18:
            /*ellipse.mouseChildren = false;
            ellipse.mouseEnabled = false;*/
        }

        var fps : TextField = new TextField;
        //uncommenting doesn't change FPS:
        //fps.mouseEnabled = false;
        addChild( fps );
        fps.text = "???";
        fps.scaleX = fps.scaleY = 3;
        var timer : Timer = new Timer( 1000 );
        timer.addEventListener( TimerEvent.TIMER, function( ... args ) : void
        {
            fps.text = _periods.toString();
            _periods = 0;
        } );
        timer.start();

        addEventListener( Event.ENTER_FRAME, function( ... args ) : void
        {
            //seems like PC is too fast to demonstrate mouse movement
            // drawbacks when he has nothing else to do, so let's make
            // his attention flow:
            for ( var i : int = 0; i < 500000; ++i )
            {
                var j : int = 2 + 2;
            }

            ++_periods;
        } );
    }
}

Solution

  • You've probably moved on to more modern problems, but I've recently struggled with this issue myself, so here's an answer for future unfortunates stuck with the problems created by Adobe's decade-old sins.

    It turns out legacy support for old-style buttons is the culprit. Quote from Adobe's tutorial on the excellent Scout profiling tool:

    "Flash Player has some special code to handle old-style button objects (the kind that you create in Flash Professional). Independently of looking for ActionScript event handlers for mouse events, it searches the display list for any of these buttons whenever the mouse moves. This can be expensive if you have a large number of objects on the display list. Unfortunately, this operation happens even if you don't use old-style button objects, but Adobe is working on a fix for this."

    Turns out Adobe never really got around to fixing this, so any large number of DisplayObjects will wreak havoc on your FPS while the mouse is moved. Only fix is to merge them somehow, e.g. by batch drawing them using Graphics. In my early tests, it seems setting mouseEnabled = false has no real effect, either.