Hack 2 Per-Pixel Text Effects

figs/moderate.gif figs/hack2.gif

Create advanced text effects and transitions that operate on the per-pixel level.

The problem in simulating per-pixel effects in Flash is that potential performance degradation limits how many fake pixels you use. You have two ways to keep this number small: keep to small images (as we did in the per-pixel transition effect hack [Hack #1]), or use the effect on an image with lots of background pixels (which you can ignore to reduce the number of fake pixels needed).

Although it's probably obvious in hindsight, it took me ages to realize that text fits the "lots of background pixels" criterion. A quick trawl on the Web suggests that it really isn't obvious because nobody else seems to be using this hack.

In this hack, we'll make the text appear to coalesce from pixels spread out over the screen. Of course, you can implement various effects using different calculations for the mask pixels' positions.

The hack comes in two parts:

  • Converting the text block's shape into 1x1 squares (i.e., our "fake pixels")

  • Animating the fake pixels

Here are the steps:

  1. Create a text field and enter some text.

  2. Press Ctrl-B (Windows) or figs/command.gif-B (Mac) or choose ModifyBreak Apart twice to turn the text field into a primitive shape.

  3. With the text still selected, press F8, and convert it into a movie clip symbol named text. Make sure the Export for ActionScript checkbox is checked and specify the linkage identifier as text. (Delete the clip instance from the Stage, as we'll be adding it at runtime from the Library with MovieClip.attachMovie( ).)

  4. For the effect to work, the movie clip's registration point must be at the top left of the text. Enter Edit in Place mode by double-clicking the movie clip; then to select all the text choose EditSelect All and enter 0 for X and Y values in the Properties panel, as shown in Figure 1-6.

Figure 1-6. Setting the registration point for the selected text symbol
figs/flhk_0106.gif


You must turn your text into a primitive shape for this hack to work using the ModifyBreak Apart command (we'll see why later), which is not ideal because it adds to the filesize. For a lot of text, it can bloat the filesize considerably. One way around this is to include each letter in your font as a separate clip containing a primitive shape and form them into sentences at runtime. Although this sounds like a lot of additional bytes to add to your SWF, remember that Flash effectively does the same thing when you save font outlines to your SWF, which you have to do whenever you want to treat font characters as graphic elements.

You also need to create a second movie clip with linkage identifier dot. The dot clip should consist of a 1 1 rectangle, with X and Y positions both set to 0 as shown in Figure 1-7 (use the Properties panel to set these because the dot will be too small to see).

Figure 1-7. The 1 1 pixel mask
figs/flhk_0107.gif


This code replicates the "zoom in from the sides with blur" effect, but this time the text really does blur (the effect is usually simulated with alpha), as shown in Figure 1-8, because we are splitting the text into pixels as part of the effect.

Figure 1-8. Per-pixel text effect, steps 1 through 4
figs/flhk_0108.gif


function mover( ) {

  this._x -= (this._x - this.x) / 4;

  this._y -= (this._y - this.y) / 4;

}



function lastMover( ) {

  this._x -= (this._x - this.x) / 4;

  this._y -= (this._y - this.y) / 4;

  if ((this._x - this.x) < 0.1) {

    dotHolder.removeMovieClip( );

    textClip._visible = true;

  }

}

// Place the text on the Stage and hide it

textClip = this.attachMovie("text", "textClip", 0);

textClip._x = 200;

textClip._y = 100;

textClip._visible = false;

// Initialize variables, including height and width

var dots = 1;

var distance = 10000;

var stopDot = true;

var height = textClip._y + textClip._height;

var width  = textClip._x + textClip._width;

// Create a dot clip for every pixel in the text

var dotHolder = this.createEmptyMovieClip("holder", 1);

for (var j = textClip._y; j < height; j++) {

  for (var i = textClip._x; i < width; i++) {

    if (textClip.hitTest(i, j, true)) {

      var clip = dotHolder.attachMovie("dot", "dot" + dots, dots);

      if (stopDot) {

        clip._x = distance;

        clip.onEnterFrame = lastMover;

        stopDot = false;

      } else {

        clip._x = Math.random( ) * distance - distance/2;

        clip.onEnterFrame = mover;

      }

      // Store the position that the dot clip has 

      // to get to (clip.x, clip.y) and move it off screen

      clip.x = i;

      clip.y = j;

      clip._y = j;

      dots++;

    }

  }

}

Ignoring the mover( ) and lastMover( ) function definitions for a moment, the remaining code places the text on the Stage and hides it. The code then initializes several variables, including those that define the height and width of our text.

The subsequent for loop uses MovieClip.hitTest( ) to find all nonempty pixels in the text and create a dot movie clip corresponding to each. Each of these dots is given an onEnterFrame( ) handler to animate the overall effect. (Instead, we could use setInterval( ) to animate the effect [Hack #1].)

Two hacks are at work in this loop code.

The first hack, using hitTest( ), is the reason we had to break apart our text. The hitTest( ) method always returns false when used with a dynamic text field (in which case it treats all pixels as empty).

The second hack is the way we check that all pixels are in their final positions. Most of our pixels are placed randomly on the screen and controlled by the event handler mover( ). The first pixel, however, is placed furthest away and also given a slightly more complicated event handler, lastMover( ). This event stops the effect when the associated pixel has moved to its final position, by which time the others will also have reached their final positions (given that they all have less distance to travel).

Although a bit of a kludge, this hack is far more performance-friendly than forcing each pixel to perform a similar check.


Final Thoughts

Although Flash text effects are all over the Web, I don't know of any that use per-pixel transitions. The cool thing about using our fake pixels is that you can use any other particle effect (such as the snow, waterfall, or star field effects [Hack #33] ) for the pixel movement routine.