Search code examples
flashperformanceprocessingframe-rate

Simple Flash test application runs very slowly compared to exact same Processing applet


So I'm gradually, painfully moving from Processing to Flash in order to hopefully develop games to a wider audience. At long last, I get a working application in Flash made that simply lets the user click to create blocks which subsequently gravitate towards the mouse. I made the exact same thing in Processing too, just to compare speeds. However, when I run the Flash version and add around 15-20 blocks, the framerate drops to 5-10 FPS. In the Processing version I can add ~60 with no noticeable slowdown. What's the deal, Flash?

Links to each version's source:

Flash version

Processing version

Here is the source for each in case you are a wizard and can help just by glowering at the code sternly and telling it to behave:

Flash version:

blocks.fla

import flash.events.Event;
import flash.display.MovieClip;

stage.addEventListener( Event.ENTER_FRAME, onenter );
stage.addEventListener( MouseEvent.MOUSE_DOWN, onclick );

var main = this;

var lastFrame:Number;

var Blocks:Array = new Array();

function onenter( e:Event ):void
{
    var time:Number = getTimer();
    for( var i = 0; i < Blocks.length; i++ )
    {
        Blocks[ i ].run();
    }
    FrameRate.text = String( Blocks.length ) + "\n" + String( 1000 / ( time - lastFrame ) );
    lastFrame = time;
}

function onclick( e:MouseEvent ):void
{
    var block1 = new Block( Blocks, main, mouseX, mouseY );
}

Block.as

package  {

    import flash.display.MovieClip;
    import flash.geom.Vector3D;

    public class Block extends MovieClip {

        var velocity:Vector3D = new Vector3D( 0, 0 );
        var position:Vector3D = new Vector3D( x, y );
        var acceleration:Vector3D = new Vector3D( 0, 0 );

        public function Block( Blocks:Array, This, x:Number, y:Number ) {
            Blocks.push( this );
            This.addChild( this );
            position.x = x;
            position.y = y;
        }

        public function run()
        {
            x = position.x;
            y = position.y;
            //position.incrementBy( velocity );
            position.x += velocity.x;
            position.y += velocity.y;
            acceleration.x = stage.mouseX - position.x;
            acceleration.y = stage.mouseY - position.y;
            acceleration.normalize();
            //velocity.incrementBy( acceleration );
            velocity.x += acceleration.x;
            velocity.y += acceleration.y;
            velocity.x *= 0.95;
            velocity.y *= 0.95;
            this.graphics.beginFill( 0 );
            this.graphics.moveTo( -10, -10 );
            this.graphics.lineTo( 10, -10 );
            this.graphics.lineTo( 10, 10 );
            this.graphics.lineTo( -10, 10 );
            this.graphics.lineTo( -10, -10 );
            this.graphics.endFill();
        }

    }

}

Processing version:

sketch_mar02b.pde

Block[] blocks = new Block[ 0 ];

void setup()
{
  frameRate( 60 );
  size( 550, 400 );
  textFont( createFont( "Verdana", 20 ) );
}

void draw()
{
  background( 255 );
  for( int i = 0; i < blocks.length; i++ )
  {
    blocks[ i ].run();
  }
  text( blocks.length + "\n" + frameRate, 0, 20 );
}

void mousePressed()
{
  new Block( mouseX, mouseY );
}

Block.pde

class Block
{
  PVector position = new PVector( 0, 0 );
  PVector velocity = new PVector( 0, 0 );
  PVector acceleration = new PVector( 0, 0 );
  Block( float x, float y )
  {
    position.set( x, y, 0 );
    blocks = ( Block[] ) append( blocks, this );
  }
  void run()
  {
    position.add( velocity );
    acceleration.set( mouseX - position.x, mouseY - position.y, 0 );
    acceleration.normalize();
    velocity.add( acceleration );
    velocity.mult( 0.95 );
    pushMatrix();
    translate( position.x, position.y );
    fill( 0 );
    rect( -10, -10, 20, 20 );
    popMatrix();
  }
}

Thanks for helping out!


Solution

  • One problem is that on every execution of .run you're redrawing the sprite's graphic box, but the sprite doesn't change at all over time. So just drawing once in the constructor is enough.

    But what if you DO have to redraw every frame for some reason? Maybe to change the color of the box over time? Well, you're neglecting to clear your old image... so every frame you just add more and more vector points to the graphics objects. So in reality while it looks like you have just one black square you actually have thousands of black squares worth of data after only a few seconds. You can clear out the graphics object like this...

    this.graphics.clear();
    

    As a micro optimization, you can assign this.graphics to a local variable...

    var g:Graphics = this.graphics
    g.moveTo(0); // and so on...
    

    Another thing I notice is that you don't appear to have time-based movement, but rather it's frame based. The blocks themselves have no idea how much time has elapsed, so they'll slow down. The alternative is to base their movement on elapsed time, which will keep them moving at the right "speed" but the app will drop frames to do it.

    Since this is a box you're dealing with, you can also use graphics.drawRect() instead of drawing a box line by line.

    In my own testing, option 1 worked the best. If you do have to redraw, make sure to do graphics.clear(), as that works almost as well even for large numbers of boxes.

    EDIT to add...

    Your example, after adding the .clear() function calls does perform very well. I should however caution you that the JVM is most certainly going to have better performance than the Flash Player. This isn't to say that people can't make highly performant Flash applications, but that the upper ceiling for performance in the Flash Player when dealing with CPU rendering is much lower than that of Java. Of course, if you're willing to live on the bleeding edge you can check out the new "Molehill" 3D apis that are capable of things like this...

    3D game on the Wii ported to Flash using molehill, running at 60fpshttp://blog.theflashblog.com/?p=2593