Article

Home » Design and Layout » Flash Tutorials » Build A Video Jigsaw Puzzle in Flash

About the Author

Mike Kantor

author_mikeK Mike is a Flash programmer and developer of rich internet applications. He develops online university courses, and provides Flash development services. His site is FlashGizmo.com.

View all articles by Mike Kantor...

Build A Video Jigsaw Puzzle in Flash

By Mike Kantor

May 19th, 2005

Reader Rating: 7.5

Page: 1 2 Next

Suppose you could convince your visitors to give their undivided attention to your company logo and message for one to two full minutes. And then watch your commercial. And then give you their email address. Sound too good to be true? Well, there is one catch: you have to be willing to chop your message up into little pieces.

In this tutorial, we'll work through the process of building a jigsaw puzzle, based on either a still image or a video. In the process, we'll cover some useful Flash techniques for loading and masking images, and for responding to user actions.

For a sneak preview of what we're building, unzip the download files and fire up sitePointPuzzle.swf. If you look in the .fla, you'll find a couple of functions not described here: randomize scatters the puzzle pieces across the Stage, and displayTime shows a running timer. We'll focus on the key features of the jigsaw puzzle application: cutting the loaded .jpg or .swf into puzzle pieces, and putting those pieces back together.

Make a Reusable Puzzle Template

First, you need to decide on the dimensions of your puzzle, in order to make the puzzle template -- the collection of shapes that fit together in the complete puzzle. The example template I've used here is 550 x 230 pixels. If you go much bigger than that, or if you use more than about 20 pieces, you risk bogging down slower machines. The actual JPG or SWF that provides the visible content will be loaded in at run-time, so we can get a lot of mileage out of a single template, reusing it with many different images.

In Frame 1 of a new Flash document, use the rectangle tool to draw a rectangle with no border, using any fill color. The color will not be visible in the final product. In the property inspector, set the width and height of the rectangle, and set its x and y position to 0. Insert an empty keyframe in Frame 2 of the timeline.

1477_fig1

Now select the lasso tool, and use it to cut out a puzzle piece from one corner of the rectangle.

1477_fig2

Choose Modify > Shape > Optimize, and find a setting that seems to work well. Optimizing the shapes will speed up the performance of the final movie, but over-optimizing will distort the shapes of your puzzle pieces. Press F8 to open the Convert to Symbol dialogue window. Give the piece the name piece0, select Movie clip, set the registration point in the upper left corner, and check Export for Actionscript. Press OK to close the window.

1477_fig3

Your freshly-minted puzzle piece is selected. Use the property inspector to give the shape the instance name a0. Cut it (Control-X), and Paste-in-Place (Control-Shift-V) into Frame 2 of the timeline. This instance serves to record the position of this piece in the final puzzle. When the Flash movie is published, a script will use this information to make a real picture-bearing puzzle piece, and then will delete this instance.

Repeat the cutting-out process until you've dissected the entire rectangle into movie clips with clip names piece0 through piece17 and instance names a0 through a17. Of course, replace 17 with the appropriate number for your own puzzle. Finally, delete the now-empty Frame 1. That completes most of the graphical interaction in this project--the rest is done with Actionscript code. If you're impatient, you can skip this stage for now, and use the puzzle template in the file puzzleTemplate300x150.fla.

Preload the Image

We need a copy of the image for each puzzle piece. If we were to issue a loadMovie call for each puzzle piece at the start, the Flash player would start multiple processes to retrieve the movie from the server. Instead, we will load the visible content once, using Flash's MovieClipLoader class. Once this first load completes, we will create the individual puzzle pieces. Because we wait for the loading to complete, the Flash player will use the cached copy of the image for all the puzzle pieces.

The MovieClipLoader class dispatches several events to any registered listeners. In this application, we create an object called loadListener, and give it onLoadProgress and onLoadComplete event handlers. These are used to update a preloader display, and to call the makePuzzle function when loading is complete. The preloader is a movie clip that contains another clip called preloader.bar, and we simply change the width of the bar to show progress.

var p : MovieClip = _root.createEmptyMovieClip("picture", 1);
var h = p.createEmptyMovieClip("holder", 1);

var loadListener : Object = new Object();
loadListener.onLoadProgress = function(target, loaded, total) {
 preloader.bar._width = 100 * loaded / total;
}
loadListener.onLoadComplete = function() {
 preloader._visible = false;
 makePuzzle();
 randomizeInt = setInterval(randomize, 3000);
}

var loader:MovieClipLoader = new MovieClipLoader();
loader.addListener(loadListener);
loader.loadClip(puzzleContent, h);

Cut the Image According to the Puzzle Template

The code for this step is in the aptly-named makePuzzle function. Here's the code for this function. (We'll examine it in more detail momentarily.)

function makePuzzle() : Void {
 // initialize the class array "pieces," that holds references to all puzzle pieces
 PuzzlePiece.pieces = new Array();
 PuzzlePiece.puzzleContent = puzzleContent;
 var piece : MovieClip;

 for(var i : Number = 0; i < numPieces; i++){
   piece = _root.attachMovie("PuzzlePieceSymbol", "piece" + i, 100 + i);
   piece.init(_root["a" + i], i);
 }  

 // Now that we have all the puzzle pieces, we dim the original image
 p._alpha = 10;
 
 /* We start loading the main content, which will be displayed after  
   the puzzle is completed.  This can be a much larger
   file, but since it loads while the user is solving the puzzle,
   it won't slow things down. */
 loadListener.onLoadComplete = null;
 loadListener.onLoadProgress = null;
 loader.loadClip(mainContent, h);
}

First, we initialize the class array PuzzlePiece.pieces, which will hold references to all the puzzle pieces. We also store the name of the .swf or .jpg to load as a class property, for convenience.

 PuzzlePiece.pieces = new Array();
 PuzzlePiece.puzzleContent = puzzleContent;

Here's the key step: we run through a loop that creates the individual puzzle pieces. Because the class PuzzlePiece is an extension of the MovieClip class, we do not use the new operator; instead, we use attachMovie to put on stage an instance of PuzzlePieceSymbol. This movie clip has no visible content, but it is linked to the custom class PuzzlePiece, as we can see in the properties window.

1477_fig4

When an instance of PuzzlePieceSymbol is created, the constructor function for the class PuzzlePiece is called automatically. This creates an instance of PuzzlePiece, but there is one problem: because we are not calling the constructor directly from Actionscript code, we have no way to pass any parameters to the constructor.

The solution is to give PuzzlePiece a public initialization function, which we can call explicitly with the needed parameters. So the loop that creates the puzzle pieces also calls the init() function of each piece, passing as parameters a reference to the original puzzle piece on the stage, and an index number:

 for(var i : Number = 0; i < numPieces; i++){
   piece = _root.attachMovie("PuzzlePieceSymbol", "piece" + i, 100 + i);
   piece.init(_root["a" + i], i);
 }

We'll examine this init() function in a moment, after finishing with the makePuzzle function. The last thing makePuzzle does is to start loading the mainContent swf into the same movieclip that we used to preload the puzzleContent. This can be a much larger file (in this example, it has music and sound effects included) without causing any delays: it will be preloaded while the user is assembling the puzzle pieces, and doesn't need to be displayed until the puzzle is finished.

 loadListener.onLoadComplete = null;
 loadListener.onLoadProgress = null;
 loader.loadClip(mainContent, h);

Create the Puzzle Pieces

Here's where the magic happens! We need to create a copy of puzzleContent, but mask it so that only the portion corresponding to a given puzzle piece is visible. This is done by the function PuzzlePiece.init():

 function init(templatePiece : MovieClip, index : Number) : Void {
   _index = index;

We save the index (which will also serve as a depth), and then load the puzzleContent into a holder subclip. This is a wise practice in general, since loadMovie() obliterates various movieclip properties, including masking and event handlers. By loading content into a subclip, we avoid wrecking properties of the main puzzle piece clip.

   holder = this.createEmptyMovieClip("holder", 1);
   holder.loadMovie(puzzleContent);

Now, for the all-important mask.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article