Give me a MovieClip I’ll give you a sequence of Bitmaps!

Ok this is another of the problems that recurs over and over again while developing rich content flash applications: Vector Animation Optimisation.

Vector animation optimisation is a good friend when you have a lot of MovieClips visible on Stage that animate at the same time.

Lets jump to a concrete example.
Say you would like to have 500 robots like the following on the screen at the same time and all animating:

Get Adobe Flash player

This is a very nice animation I found on the internet which I don’t know anything about. Like I don’t really now the structure of each frame, I don’t know how many MovieClips composite this animation, etc.
I’m mentioning this because a lot of the times, graphics are created to be easily animated, or easily expanded, and most of the time that approach clashes with optimisation. (Why? because you can end up with an infinite amount of nested MovieClips + Masks + complex strokes and fills)
I’m not criticising designers, because I think I would do the same if it was me doing that job: I always want to make my life easy!

So here is the result of having 500 instances of that MovieClip attached to the Stage and animating them at the same time (move the mouse pointer on top of the flash movie to start)

Get Adobe Flash player

Notice that the target frame rate the swf was published to is 31 FPS.

You can see that the swf is running at about 1 FPS (At least on my machine, let me know if it’s different for you).

(cacheAsBitmap won’t help in this case because the cached bitmap will be invalidated every time the the next frame is loaded)

This is not good enough … BitmapData help us!!!

How to optimise this animation….

a) ask the designer to reduce the number of nested MovieClips
b) ask the designer to simplify strokes and fills
c) ask the designer to convert each frame into bitmaps and remove all the MovieClips

and these could be reasonable answers:

a) If I do that then it’s going to be a nightmare changing the animation
b) I don’t want to loose the level of details
c) Do I need to do this for each character? are you having a laugh? I hope you are going to give me a one click tool to do that!

so I don’t think those could be long term solutions.

And here is when BitmapData joins the circus.

What I have done is creating a function which from a given MovieClip it gives back a Vector of BitmapData objects. The Vector contains a number of items equal to the number of frames of the given MovieClip, and each Item is a bitmap snapshot of each frame.
Then I feed this Vector to another class which emulates the MovieClip class interface (e.g. gotoAndStop(frameNumber), play(), stop(), etc.),it copies the current frame’s bitmap into a Bitmap Object. I create 500 instances of this last class and attach them to the stage.
Here is the result (move the mouse pointer on top of the flash movie to start):

Get Adobe Flash player

the frame rate stays at about 27 FPS, it’s not 31 FPS but it’s good enough.
this is a good improvement.

so what is the trick?

the trick is that I create exactly 500 Bitmap objects and only one copy of each frame of the entire animation is in memory, then each frame gets copied in each of the 500 MovieClips.

For the first example we have 500 instances of the Robot MovieClip on the stage. Each instance has its own timeline and Flash Player needs to render each frame for each instance.

While in the second case we create just one Vector that contains all the frames, which have been already rendered as BitmapData. Then we iterate through the Vector and we copy the current BitmapData in all the 500 Bitmap instances on the stage.

This works well when all the animations look the same, if you need 500 different animations you still get a goot frame rate but the memory usage will go up sharply. (You end up with a copy of each frame of each animation loaded in memory)

Another factor that can influence the frame rate is the size of the stage. If I take the swf above and publish it with a stage much bigger (say 1024×768) it will run at a lower frame rate even if we are using bitmaps. This is because Flash player needs to render a bigger space, taking longer.

Here you can find the class to convert a MovieClip into a Vector of BitmapDatas (MovieClipToBitmap.as) and also the class to control the Vector like a MovieClip (BitmapMovieClip.as).

Vizio

This entry was posted in AS3, experiments, Flash, Thoughts, Tools. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • http://twitter.com/chrisgannon Chris Gannon

    Thanks! These are much better than my experimental classes!

  • Anonymous

    you are welcome :) and if you got any idea on how to improve them just let me know!

  • http://twitter.com/chrisgannon Chris Gannon

    I am wondering if there is a way to implement copyPixels() instead of draw() as draw() is very slow. Not really sure if this would help actually….However I just created a quick iPhone app using these classes to test the performance (it’s a simply star shape rotating) – I placed 10 instances on the stage and the performance is pretty bad :( It may be due to the alphas required but I am still testing. Any ideas?

    This is my (stripped down) code btw;

    //SquareAnim is the library linked vector star movieclip

    var t:Vector. = MovieClipToBitmap.createBitmapFrameSequence(new SquareAnim(), 100, 100);
    for (var i:int = 0; i <10; i++) {

    var f:BitmapMovieClip = new BitmapMovieClip(t);
    addChild(f);

    f.x = Math.random() * stage.stageWidth/2;
    f.y = Math.random() * stage.stageHeight/2;
    f.play();

    }

  • http://twitter.com/chrisgannon Chris Gannon

    …and just ignore the ‘closing bitmapdata tag’ – this comment box has added it!

  • Anonymous

    Hi Chris,

    the call to the draw method happens just once, when you create the Vector. so that could slow down the startup of the app but after that I just use the copyPixels method.

    Unfortunately I cannot test your code as I don’t have a CS5 license to publish for iPhone, but it looks ok to me.

    let me double check, I’ll get back to you soon.

  • Anonymous

    …and just ignore the ‘closing bitmapdata tag’ – this comment box has added it! :) it happened to me as well!

  • Anonymous

    Hi Chris,

    I’ve found this topic on the Adobe’s forum

    http://forums.adobe.com/message/3128302#3128302

    it looks like the Bitmap technique should work fine on iPhone.

    Still let me know if you find the problem

  • http://twitter.com/chrisgannon Chris Gannon

    Thanks – that article was actually my initial starting point!I’m currently hacking and slashing at your classes to try and force some kind of frame caching – I’ll let you know when I’ve gone totally mad and thrown my iPhone out the window for being so slow :)

  • LizGuest1

    I have a quick question, and perhaps I’m just slow, but where do you do the action script for this?
    Are you just calling the class files from the main timeline in flash file? Or are you attaching these classes to each movie clip you wish to convert?

    Thanks!

  • Anonymous

    Hi there,

    you should be able to call the MovieClipToBitmap.createBitmapFrameSequence() from the timeline and pass in the MovieClip you want to convert to bitmaps. Then you need to create a BitmapMovieClip object to which you pass in the Vector of bitmaps you’ve just generated using the MovieClipToBitmap.
    The idea is that you need only to call the static function MovieClipToBitmap.createBitmapFrameSequence() which is in charge of converting any MovieClip to a a vector of bitmaps, then for each of those vectors you need a BitmapMovieClip Object to control them.

    e.g.

    //say myMc1 is a Movieclip on the stage

    //you create the bitmaps for each frame of the myMc1 movieclip
    var bitmaps:Vector. = MovieClipToBitmap.createBitmapFrameSequence(myMc1, 100, 100);

    //you now need to create a BitmapMovieClip to be able to control the sequence of bitmaps
    var myMc1UsingBitmaps:BitmapMovieClip = new BitmapMovieClip(bitmaps);

    //add the new BitmapMovieClip to the stage
    addChild(myMc1UsingBitmaps);

    //play the sequence of bitmaps
    myMc1UsingBitmaps.play();

  • Anonymous

    Sorry just noticed a little error here:
    var bitmaps:Vector. = MovieClipToBitmap.createBitmapFrameSequence(myMc1, 100, 100);

    I manually specify the width and height of the bitmaps to 100, better if you do the following:

    var bitmaps:Vector. = MovieClipToBitmap.createBitmapFrameSequence(myMc1, myMc1.width, myMc1.height);

    let me know how you get on with it

  • LizGuest1

    Hi Vizio!

    It took me a bit to get started on this conversion but I’m finally there. However, the first movie clip I’m trying to convert to bitmap is throwing this error: “BitmapMovieClip – No Vector. specified or no elements in the Vector!!!” Which I noticed is from your (awesome!) class file. I guess I don’t totally understand what that means, I don’t normally go this heavy into actionscript, and it’s been a while since I’ve coded in general.

    My movie clip has animations within it, and is a mix of imported .ai artwork, a layer mask, one stop(); … Just want to make sure that this isn’t part of the issue. (I’m trying to have mouse over effect on each movie clip but the swf lags terribly when played and I think it’s all the imported artwork. That’s why I’m hoping to this bitmap conversion.)

    Sorry for all the trouble and thanks for your help!

  • Anonymous

    Hi there,

    are you able to send me (or upload somewhere) the file with just the movieclip you want to convert?

    Do you want to keep your artwork in layers to be able to modify them in flash?
    I ask this because you could just import your artwork as bitmaps. That will solve all the problems without using my classes.

  • LizGuest1

    Right now everything is in layers for the sake of the tweens. Here is a link to a movieclip I uploaded. But there are about 10 of these in varying sizes. All are similarly constructed, and when put together in the main flash file, they really lag.

    http://www.megaupload.com/?d=VI3ZC65N

    Thanks for all your help!

  • Anonymous

    Hi Liz,

    Thanks for the example I had a look at it and I almost fixed it. I had to amend my classes as they didn’t consider masking (masks when moving can change the dimensions of the movieclip), also I had to add some more methods.

    In the fla file you’ll see that I’ve created a new MovieClip Container which is on the stage, and I put inside your movieclip (wrdGroup_mc). This is because my BitmapMovieclip Class doesn’t support events yet so I needed something else to listen to the mouse events and control the bitmapMovieclip object.
    All the amended classes are included in this zip file:

    http://dl.dropbox.com/u/4656840/exampleMC_amended.zip

    Unfortunately it looks like the animation itself is not great as even when converted to bitmaps the animation doesn’t look smooth.
    If you look inside the wrdGroup_mc, and you manually go through the animations frame by frame, you see that the yellow filling jumps step by step each frame.
    Maybe you should try and export it in a different way from illustrator or create the animations directly in flash.
    Sorry I cannot help you more.

  • Chiken

    Hi there, thank you very much for the awesome work ^^.

    My problem is that when I captured the frames inside the Bitmapdatas, certain animation frames will be missing.

    This is because say if you have a MovieClip that has another Movieclip inside one of its frame and runs on its own ( so that you can make animations appear/disappear, guess it’s a designer trick to make complex animations ), so then when I do the capturing, those frames will be missing ( because they was not there when I captured the MovieClip ).

    This has puzzled me for a while and dont have a solution yet. If you can help me with some suggestions I would be very grateful ^^

    Thank you.

  • Anonymous

    Hi there,

    Yeah that is a known issue, right now this solution doesn’t support nested movieclips.

    I’ll have a think about it and let you know.

    Cheers
    Vizio
    Simone

  • http://www.facebook.com/greg.lindquist Greg Lindquist

     I love these classes! I never thought to store them in a vector, but I’m having a bit of trouble extending these classes to include smoothing. Is it worth the effort?

    Thanks.

  • vizio

    Hi Greg,

    I’m glad you’ve found them useful :)

    Do you mean image smoothing? I thought it was already set. I need to have a look at it.
    If not adding it should be pretty straight forward. Let me see I’ll get back to you.

  • Anonymous

    Hi Greg,

    I’m glad you’ve found them useful

    Do you mean image smoothing? If so they should already be smooth.

    If you look in MovieClipToBitmap.as I already set the smoothing param to true when I draw the bitmap (line 102)

    is that what you meant?

blog comments powered by Disqus