Articles Archive
Articles Search
Director Wiki
 

Flash + Director = not quite so slow

July 25, 2000
by Gary Rosenzweig

Two weeks ago I wrote a column about how slow Flash members inside Director movies are. They are slow; no one disagreed. However, I did make a mistake (actually, a double mistake) in my method. The first mistake was to assume that the little-known Flash member property static was the same as the pausedAtStart property. It would seem to make sense that if a Flash member were paused, Director would treat it as if it were static. Not so. They are separate properties, and they give different results in the speed test.

The double mistake came when I used the loop property, rather than the pausedAtStart property, in my tests. If you check that old column, you can see that the demo movie allowed you to see the loop property. I'm not sure why I did that, except that I was thinking in terms of single-frame Flash movies. In that case, loop and pausedAtStart are not very different.

Here is an updated test movie. This provides controls for both pausedAtStart and static.

Using the "Flash over Flash" test, with high quality on and pausedAtStart and static off, I got the result of 3900 milliseconds. Changing the pausedAtStart to on, the results were the same. However, turning static on got me 1400 milliseconds. Quite an improvement!

The champion, however, is still "Bitmap over Bitmap" with 1100. This isn't quite as impressive a margin as in the previous tests, however. Also, note that I did these tests on my G3 Powerbook this time, not my G4 desktop. So the numbers from the old column and these numbers shouldn't be compared -- but their ratios should.

I did the same tests in Shockwave on an 800 MHz Pentium III with a fast video card. Both "Flash over Flash" and "Bitmap over Bitmap" came out at 300 milliseconds when the Flash static property was turned on. A tie? Well, impossible to tell, since 300 milliseconds to go about 300 frames means that the 999 fps limit was reached in both cases. The Powerbook test was a little more revealing.

Rather than just leave it at "Flash is still a little slower than bitmaps," I want to propose a solution involving Imaging Lingo. You can get the image property of a Flash member, just as you can get the image property of a bitmap. Once you have this image, you can create a new bitmap with it. This bitmap will look exactly like the Flash member, but it will be faster.

Here is a short behavior that does this. It will take the image of the Flash member, create a new bitmap, and place the image in it. Then, it will swap the Flash member for the bitmap in the sprite. To be neat, when the sprite is done it will erase the bitmap.

property pMember

on beginSprite me

  -- make new member
  pMember = new(#bitmap)

  -- copy image to member
  pMember.image = sprite(me.spriteNum).member.image

  -- set the sprite to this new member
  sprite(me.spriteNum).member = pMember

end

on endSprite me
  -- sprite done, get rid of the evidence
  erase pMember
end

The advantage of this technique over using just a bitmap to begin with, is that you don't have to create and store a bitmap in your movie. This should cut down on file size. Plus, it might make it easier for a programmer to work with a Flash artist. When the Flash artist delivers a new Flash movie, nothing has to be done other than importing it into the Director movie. The conversion happens on the fly. the other advantage, of course, is a slight speed increase. (Note: This works great in Director, but apparently it does not work at all in Shockwave! All I get, Mac and PC, is a black box instead of the Flash member's image. I tried all sorts of workarounds, like having the bitmap already on the Stage, forcing the useAlpha of the new bitmap to TRUE, etc. None of these work. If anyone finds a solution, let me know. Otherwise, the next technique will work for static images as well as animated ones).

For animated Flash movies, you can do something very similar. Instead of just converting the initial frame of the Flash member to an image, you can create a list of images from each frame in the Flash movie. A nice way to do this would be to loop through the frames of the Flash member, grab an image from each frame, store it in a list, and then replay the list of images through a single bitmap. Unfortunately, there is a problem with this. You can't tell a Flash member which frame to go to. It is always on the first frame.

But wait a minute, what about the goToFrame Flash member command? Well, that is a sprite command, not a member command. You can tell a Flash sprite to go to any frame you want, but the member will still be at frame 1.

One way around this would be to capture the image of the sprite, not the member. Unfortunately, you can't do this. But you can capture the image of the Stage. So, you can display the member on the Stage in a sprite, tell it to goToFrame for each frame, grab the image from the Stage, and build the list that way.

The major disadvantage of this is that the user will see this happening. You can find a way to mask this, either by a "rendering images..." message or by using the image capture as an intro animation.

Once the images are in a list, you can set the image of a temporary bitmap to each image in the list. To make this match the frame rate of the original Flash movie, you can use a timer to determine when the next image should be displayed. Here is the code for this behavior.

property pGotImages, pMember, pNumberOfImages
property pImages, pImageNum, pFrameRate, pNextFrame

on beginSprite me

  -- can't update stage during beginSprite, so set flag to do it on first exitFrame
  pGotImages = FALSE

end


on getImages me

  -- save original loc, and then set sprite to middle of Stage
  origLoc = sprite(me.spriteNum).loc
  sprite(me.spriteNum).loc = point((the stage).rect.width/2,(the stage).rect.height/2)

  -- loop through frames of Flash movie and create list of images
  pImages = []
  pNumberOfImages = sprite(me.spriteNum).member.frameCount
  pFrameRate = sprite(me.spriteNum).member.frameRate

  repeat with i = 1 to pNumberOfImages
    sprite(me.spriteNum).goToFrame(i)
    updateStage
    image = (the stage).image
    add pImages, image.crop(sprite(me.spriteNum).rect)
  end repeat

  -- reset location of sprite
  sprite(me.spriteNum).loc = origLoc

  -- create new member and set sprite to use it
  pMember = new(#bitmap)
  sprite(me.spriteNum).member = pMember

  -- set image properties
  pImageNum = 0
  pNextFrame = 0

  -- start showing images
  showNextImage(me)

  -- remember that we don't need to do this again
  pGotImages = TRUE

end


on showNextImage me

  -- see if it is time for next image
  if the milliseconds > pNextFrame then
    
    -- increment image, loop back if past last
    pImageNum = pImageNum + 1
    if pImageNum > pNumberOfImages then pImageNum = 1
    
    -- set image
    pMember.image = pImages[pImageNum]
    
    -- set time for next image
    pNextFrame = the milliseconds + 1000/pFrameRate
    
  end if

end


on exitFrame me

  if pGotImages then
    -- see if time for next image
    showNextImage(me)
  else
    -- initialize
    getImages(me)
  end if

end


on endSprite me

  -- sprite done, get rid of the evidence
  erase pMember

end

This behavior is pretty good at imitating an animated Flash movie, taking into account the frame rate and all. You can even take into account things like Flash member quality, looping, pausedAtStart, and goToFrame calls by adding additional functionality to the behavior above. I'll leave those as an exercise for the reader.

Here is a demo movie that uses this technique. It times the movement of an animated Flash member across the Stage. I used the two-frame animated biplane from the Flash library for the example.

Director 8 sample movies are available for download in Mac or PC format.

First, let's look at the results with a static image. It takes 15000 milliseconds to cross the screen, even with pausedAtStart and static properties turned on. Converting it to a bitmap first gives the result of 6000 milliseconds. Quite an improvement. This large, irregular shape shows a much bigger gap between using a bitmap and using a Flash movie than my previous red ball tests.

Now, let's try it animated. The result for the Flash movie is the same: 15000 milliseconds. That is interesting in itself. The animated Flash movie is as slow as the "static" one. So much for the static setting having much effect on a Flash movie like this. I got similar results in Shockwave on the PC.

Now, let's use the nifty behavior that converts the animation to a list of images. It takes 7000 milliseconds to cross the Stage. That's only slightly more than the non-animated version. This shows that the bitmap image swaps are taking up only a little bit of time. This is good news, as we now have a way to double the speed of this Flash animation.

Better yet, it is a nice, neat way of speeding up Flash -- no leftover members, no conversion process, just a simple behavior. We can actually do the same thing with those slow text members... but I'll save that for another week.

Gary Rosenzweig's new book "Special Edition Using Director 8" is now available. It's the most comprehensive guide to Director ever, including tons of examples and demo movies. It's suitable for novices and experts alike. More information about the book can be found at http://clevermedia.com/resources/bookstore/book5.html. It can be purchased there, or in your local bookstore.

Gary Rosenzweig is the Chief Engineer, founder, and owner of CleverMedia, a game and multimedia development company in Denver, Colorado. He is the author of ten books on Macromedia Director and Flash, including his latest, Special Edition Using Director MX.

Copyright 1997-2024, Director Online. Article content copyright by respective authors.