2
May
2006

How to make a Flex effect: Explode v 0.5

[The explode effect has been updated for the beta 3 version of the player. You can find the code here. –Sho, May 11, 2006]

The explode effect overlays a copy of an object over the object itself and zooms it larger as it fades. It’s simple enough to take you through it line by line, but it’s complex enough that I think it’s instructive. I know that when I first wrote it, it helped me understand more about how bitmaps, popups, and effects work.

NOTE: Requires Flash Player 8.5 beta 2.
[Demo – Explode effect]

~

Creating the bitmap

Let’s start by creating the bitmap that will overlay our effect target. There are a number of reasons for using a bitmap here:

  1. I don’t want to zoom the object itself; I want to zoom a copy of it.
  2. I could make an exact copy of the object (for example, I could make a new Button if the target was a Button), but it is hard to clone a UIComponent without knowing what type of object it is ahead of time.
  3. Even if you can clone the object successfully, zooming the real thing can look strange in terms of layout and fonts. Zooming a bitmap will look pixelated, but will otherwise behave in a predictable way.

To understand how bitmaps work, you need to understand two classes: BitmapData and Bitmap. The BitmapData contains the raw 1s and 0s for the bitmap data. The Bitmap object is the display list object that renders this data.

Let’s write a function called BitmapUtil.render() that will create a bitmap for a UIObject.

public class BitmapUtil 
{
    // Naive version of the render() function that returns
    // a Bitmap object.
    //
    static public function render(target: UIComponent) : Bitmap
    {
        // Create the bitmap data object with the right size.
        var data : BitmapData = 
            new BitmapData(target.width, target.height, true, 0);

        // Draw the target object into the bitmap data.
        data.draw(target);
			
        // Create a new bitmap object associated with this data.
        var bitmap: Bitmap = new Bitmap(data);

        return bitmap;
    }
}

This works fine, but as it turns out, dealing with raw Bitmap objects in Flex is a bit of a pain. Bitmap objects are display objects from the Flash Player API, and do not inherit from UIComponent. To make this easier, let’s wrap a UIComponent around this thing. The easiest way to do that is to use the Box object.

public class BitmapUtil 
{
    // New version of the render() function that returns
    // a UIComponent.
    //
    static public function render(target: UIComponent) : UIComponent
    {
        // Create the bitmap data object with the right size.
        var data : BitmapData = 
            new BitmapData(target.width, target.height, true, 0);

        // Draw the target object into the bitmap data.
        data.draw(target);
			
        // Create a new bitmap object associated with this data.
        var bitmap: Bitmap = new Bitmap(data);

        // Create a box object. This is one of the most 
        // simple forms of UIComponent.
        var box : Box = new Box;

        // Add the bitmap to its list of children. We must 
        // use the "rawChildren" list, because the bitmap
        // is a raw display list object, not a UIComponent.
        box.rawChildren.addChild(bitmap);

        // Set the size of the box correctly.
        box.width = target.width;
        box.height = target.height;

        return box;
    }
}

Floating the bitmap above the target

For this effect, we want the bitmap to float above the target. This sounds like a perfect job for the popup manager. Let’s create a function called BitmapUtil.renderAsPopup() that does everything that the previous function did, and then floats the bitmap above the target.

static public function renderAsPopup(target: UIComponent) : UIComponent
{
    // Use the render() function to create a bitmap object.
    var result : UIComponent = render(target);

    // Use the popup manager to float the bitmap above
    // the rest of the application.
    PopUpManager.addPopUp(result, Application.application, false, true);

    // Get the location of the target in global coordinates.
    var p : Point = new Point(0, 0);
    p = target.localToGlobal(p);

    // Set the position of the popup to these coordinates.
    result.x = p.x;
    result.y = p.y;

    // Return the floating bitmap to the caller.
    return result;
}

Creating the effect

Now, we want to create an effect that creates and animates this floating bitmap. Because our effect is basically just three existing effects running in parallel, let’s have it extend the Parallel class.

The main thing we have to do is to override the play() method. When our version of play() is called, we create a set of parellel effects to play, based on the target.

The target of the play() function can come from three places. First, it may have been passed to us as an array. Second, it may have been attached to the targets property, which is of type Array. Third, it may have been provided as a single object using the target (singular) property. We want the logic in this function to treat all three of these cases the same, so we deal with it like so:

public override function play(theTargets:Array=null, reversed:Boolean=false) : Array
{
    if (theTargets == null)
        theTargets = targets;

    if (theTargets == null)
    {
        if (target != null)
            theTargets = [target];
    }
    // from this point onwards, just use theTargets as
    // the array of targets.
}

The next step is to create a zoom, fade and move for each target. The code looks like this:

// Delete all current children of this effect.
this.children = [];

for each (var thisTarget : UIComponent in theTargets)
{
    var proxy : UIComponent;
					
    // Create a bitmap proxy for this target.
    proxy = BitmapUtil.renderAsPopup(thisTarget as UIComponent);

    // Create a zoom, fade and move effect for this bitmap
    // and add them as children of this effect.

    var zoom : Zoom = new Zoom();
    zoom.zoomWidthTo = zoomFactor;
    zoom.zoomHeightTo = zoomFactor;
    zoom.duration = duration;
    zoom.target = proxy;
    addChild(zoom);
					
    var fade : Fade = new Fade();
    fade.alphaTo = 0;
    fade.duration = duration;
    fade.target = proxy;
    addChild(fade);
					
    var move : Move = new Move();
    move.xBy = - (zoomFactor-1) * thisTarget.width / 2;
    move.yBy = - (zoomFactor-1) * thisTarget.height / 2;
    move.duration = duration;
    move.target = proxy;
    addChild(move);
}

We then play the event. We do this by calling super.play()

super.play(theTargets, reversed);

Finally, we need to return an array of all the affected properties. Since this effect uses a bitmap overlay and doesn’t do anything to the original objects, we just return an empty array.

return [];

Cleaning up after ourselves

The effect will actually run at this point, but we are never getting rid of the bitmaps we create.

To get rid of the bitmaps, we need to trap the “effectEnd” event. We do this in the constructor.

public function Explode(target: Object = null)
{
    super(target);
    addEventListener(EffectEvent.EFFECT_END, _onEffectEnd);
}

In the effect end handler, we remove all the proxies we created during the play() function. To do this, we need to define an array called proxies that holds all the proxies that we have created. We make this protected instead of private because if someone were to ever create a subclass of Explode, he or she would probably need access to this array.

protected var proxies : Array = [];

We fill up the proxies array as we create the bitmap proxies in the play() method above

for each (var thisTarget : UIComponent in theTargets)
{
    var proxy : UIComponent;
					
    // Create a bitmap proxy for this target.
    proxy = BitmapUtil.renderAsPopup(thisTarget as UIComponent);

    // Add the proxy to the proxies array.					
    proxies.push(proxy);

    // Do the rest of the logic above here.
}

And we remove the proxies when the effect is over.

private function _onEffectEnd(event: Event) : void
{
    for each (var proxy: UIComponent in proxies)
    {
        PopUpManager.removePopUp(proxy);
    }

    // Clear the proxies array.
    proxies = [];
}

The full effect

That’s all there is to it. The full code is listed here. Now that you’ve been through it line by line, it should be pretty easy to understand.

NOTE: Requires Flash Player 8.5 beta 2.
[Demo – Explode effect]
[Source code]

4 Responses to “How to make a Flex effect: Explode v 0.5”

  1. bob pardoe

    This needs fixing for the beta 3 bug

    In beta 3, the Timer class is located in the flash.utils package and not
    flash.util

    thanks

    BOb

  2. kuwamoto.org » Blog Archive » Example code updated for beta 3

    […] Explode: An effect that takes a bitmap copy of the target object and zooms it larger as it fades away. Comprehensive explanation of the code can be found here. […]

  3. sho

    Updated code posted here.

  4. Salehein

    Thanks … it was a gr8 help. b4 i found ur code, life was so difficult…
    thanks a lot

Leave a Reply