Hack 6 A Tree Grows in Brooklyn 
Create a random tree generator.
This hack creates a natural-looking
tree using the usual suspects (fractals/recursion/repeat-and-scale
algorithms). In the next hack, we'll create movement
using an embedded hierarchy of movie clips.
For those of us who prefer speaking English, we're
going to grow a tree and make it sway in a breeze [Hack #7]. We will do this by
re-creating natural phenomena in code.
The first time I went to Flash Forward (http://www.flashforward2004.com), Josh Davis
talked about what made him tick. To paraphrase his 45-minute
presentation into a single sentence, he said, "Look
at nature, and see what it throws up at you, and then think what you
can do with the result."
The Web is full of such experiments, and no hacks book would be
complete without one or two such excursions.
Fractals
To
get the following information on
nature, I had a short conversation with my girlfriend Karen. We have
a neat division of labor: she deals with the garden, and I deal with
the computer.
Here's what I learned without having to set foot
outside. Trees follow a very basic pattern, and this is usually
regular. A branch will be straight for a certain length and will then
split. The thickness of the parent branch is usually related to the
branches that grow from it—normally the cross-section is
conserved (the total thickness of the trunk is roughly the same as,
or proportional to, the thickness of the branches that sprout from
it). This means that a twig grows and splits in exactly the same way
as a main branch: the relative dimensions are the same. You know that
this self-same process between tree and twig is going on because, if
you plant a twig (well, if Karen plants it; mine always dies), you
end up with a tree.
With this in mind, I created a random tree generator. Two example
results are shown in Figure 1-28.

Both trees (and many more) were created using the same code. Here is
treeGen.fla,
which is downloadable from the book's web site:
function counter( ) {
if (branchCounter == undefined) {
branchCounter = 0;
}
return (branchCounter++);
}
function grow( ) {
// Grow this limb...
this.lineStyle(trunkThickness, 0x0, 100);
this.moveTo(0, 0);
this.lineTo(0, trunkLength);
// If this isn't the trunk, change the angle and branch size
if (this._name != "trunk") {
this._rotation = (Math.random( )*angle) - angle/2;
this._xscale *= branchSize;
this._yscale *= branchSize;
}
// Grow buds...
var seed = Math.ceil(Math.random( )*branch);
for (var i = 0; i < seed; i++) {
if (counter( ) < 3000) {
var segment = this.createEmptyMovieClip("segment" + i, i);
segment.onEnterFrame = grow;
segment._y = trunkLength; }
}
delete (this.onEnterFrame);
}
// Define the trunk position and set the onEnterFrame handler to grow( )
this.createEmptyMovieClip("trunk", 0);
trunk._x = 200;
trunk._y = 400;
trunk.onEnterFrame = grow;
// Tree parameters
var angle = 100;
var branch = 5;
var trunkThickness = 8;
var trunkLength = -100;
var branchSize = 0.7;
The basic tree shape is defined by
the parameters in the last few lines of the listing:
- angle
-
The maximum angle a branch makes with its parent
- branch
-
The maximum number of buds (daughter branches) any branch can have
- trunkThickness
-
The thickness of the tree trunk
- trunkLength
-
The tree trunk's length
- branchSize
-
The ratio between the daughter branch and the parent branch (which
makes branches get smaller as you move away from the trunk)
First, we create the trunk and set its position. We then attach
grow( ) as its
onEnterFrame event handler. As its name
suggests, grow( ) makes our empty movie clip
grow by doing two things. First, it creates our branch by drawing a
vertical line of height trunkLength and thickness
trunkThickness. If we are currently drawing the
trunk, we leave it as-is, resulting in scene 1. If we are not drawing
the trunk, we also rotate it by +/- angle, as seen
in scene 2, and scale it by branchSize; as seen in
scene 3; all are shown in Figure 1-29.

The code then creates between 1 and branch new
buds. The hacky part is that these buds are given the same
onEnterFrame event handler as the current one,
namely grow( ), so in the next frame, the buds
grow their own buds and so on. Here is the portion of grow(
) that spawns a new movie clip for each bud and assigns
the onEnterFrame event handler. Our tree could
create new branches forever, but we need a limit; otherwise, Flash
slows down and eventually crashes. To prevent this, the function
counter( ) is used to limit the total number of
branches to 3,000.
var seed = Math.ceil(Math.random( )*branch);
for (var i = 0; i < seed; i++) {
if (counter( ) < 3000) {
var segment = this.createEmptyMovieClip("segment" + i, i);
segment.onEnterFrame = grow;
segment._y = trunkLength; }
}
Finally, grow( ) deletes itself, as it needs to
run only once per branch.
So, we are using a self-calling function (or, rather, one that
creates copies of branches that contain the same function attached to
them) to create our fractal tree. Not only do we have a tree
consisting of branches and sub-branches, but we also have the same
hierarchy reflected in the movie clip timelines. You can see this by
using the debugger (although you will have to set the maximum number
of branches down from 3000; otherwise, you will be in for a long
wait!).
The result is vaguely oriental in its simplicity. However, it
doesn't involve motion graphics, and static Java
tree generators are a dime a dozen. Therefore, we add movement to our
tree in the next hack.
|