Please visit Straf Spul's main site. This is the nerdy corner.

Unique Random

Picturepusher is generic picture slideshow in 3D, which interacts with the user by letting him push over each picture by clicking it to proceed to the next picture.
The swf loads it's images dynamicly from a simple xml file. The images are then applied as textures to planes through Papervision objects.

First some pictures

First you will need to prepare some pictures for the slideshow. In this code we will use the following dimensions for the pictures:
width: 640 pixels, height: 480 pixels, format: 4:3
These dimensions are also known as VGA. You can find these settings on your digital photocamera, which saves you the trouble of converting them in Photoshop or the Gimp or Paint or whatever...
When you look in the API of Papervision, you will notice that these dimensions also are the default values for the viewport object.

When testing this project in the standalone flash-player, the movie will use these dimensions by default. Later when you embed your movie in a webpage, you will be able to change the width and height of these pictures with flashvars. The size of the flashmovie and the size of the pictures may then differ. For instance you could define a smaller size for the pictures which will result in a red carpet like effect.
Every picture must have the same width and heigth.

When you have collected all the jpg or png files in a folder, we are going to tell the flashmovie where it can find all those beautiful pictures you selected by creating a ...

Very basic xml-file

I called my xmlfile data.xml and i advise you to give it the same name and place it in the same folder where you are alse going to drop the swf-file. This enables you to test the swf-file locally and not on a server. Later when you are embedding the flashmovie in a web-page, you will be able to set the xmlfile's location via a flashvar.
The xml-file has to be structured with the following tags.

The first line of the xml is a standard header.
The second line and the last one, who are called stuff, are there to wrap it up. You can rename that tag if you want because its name isn't mentioned in the actionscript code.

The tag that really matters is the picturePath tag.
This tag is transformed into an array by actionscript and holds all the paths where flash can find it's pictures. These paths can be relative or absolute or even refer to pictures on a different domain. As you can see all my pictures are stored in a folder called img.
The order in which you place all elements of the picturePath tag determines in which order the pictures will be displayed. There is no random shuffle in the order.

But enough for the static art of pictures lets get down to programming the movement and the interactivity with...

One single actionscript file

If you don't feel like programming, you can download the zip file and procceed to the embedding-section.

If you plan on tweaking the as and compiling the swf with Flash or maybe mxmlc, you can download the as file or tab into the textarea below, select everything by hitting Control a and copy paste that text into an as-file.

Before compiling the code

When you read the first lines of the actionscript code you will notice that the program includes a lot of different external classes. The first nine are some basic flash classes, which normally won't trouble you with any compiler-warnings. The rest of them however are derived from Papervision3D. If you haven't downloaded it you can find it at googlecode I used the Papervision3D_2.0.883.zip
So before compiling be sure to have the papervision classes in your classpaths!!
In Flash see Edit > Preferences > Actionscript > actionscript 3.0 settings
or in FlashDevelop see Project > Properties > Classpaths.

Okay, now it's time to discuss the...

Key variables

All of the key variables are defined as public properties of the picturepusher class. This main class extends the MovieClip class, because in contrary to a Sprite, contains a timeline, which can allow you to add actionscript to a frame in the IDE timeline. So in my experience as animator, it is more usefull to use the MovieClip class instead of the Sprite class as DisplayObjectContainer.

Here is the first set of variables:

These variables will be used for the papervision viewport, renderer, scene and camera. The function init3Dengine creates the four objects and every frame an event fires the function onEnterFrame, which causes the renderer to render the scene.

The objects on the scene are represented by the following variables:

pictureWidth and picturHeight are the default values in pixels for the width and height of the panels that will contain the pictures. Both variables will be overwritten if you set them as flashvars, when you embed the swf into a web-page.

track is basicly an object that you could compare with an invisible treadmill on which all panels are placed with a space between them equal to their height. This track is then moved along the z-axis. The method of using this track as a wrapping container for the other objects, is (in animation-mids) refered to as parenting. This allows us to move all the objects at the same time, without having to change all there positions seperatly.

trackOffset is a point along the z-axis where the images will appear at their normal dimensions. If the pictures have the same dimensions as the flashmovie they will completely fill up the screen.
In contrary to the normal 2D coördinate-system of Flash, Papervision uses a 3D coördinate-system, with a z-axis. Where in Flash the coördinates start in the top left corner of the screen, in Papervision the coördinates start in the middle of the viewport and the distance along the z-axis between this point and the viewport is (by default) 650 pixels. Although it is a little bit awkward to talk about pixels when talking about depth.

The trackHome property is the point in space where the track always will be attracted to. When a user clicks a panel the value of trackHome becomes changed and all pictures slide until the next one is blocking the viewport. More about the rules of attraction later...

We also need to store all our planes in a public array, where we can reach them. We save them in the panel_arr. The integer currentPanel helps us to keep track of which panel we are currently viewing and numberPanels is the total number of panels. So when currentPanel exceeds numberPanels: the script knows that it has to lift all panels back up and slide to the first panel again.

The last three variables of this set (forwardID_arr, reverseID and currentReverse) are there to keep track of the setTimeout and setInterval functions.

If you kept track of which variables i already explained you might have noticed that i skipped two variables. I'm talking about these two here:

paramObject is a variable of the basic type Object which we will use to store the flashvars and pictureXML will store our XML data. How we use all these variables will become clear when we discuss the ...

Key functions

The first function of a program is the constructor or sometimes refered to as the entry-point. This function gets called (and only this function), when the program executes and creates the picturepusher movieclip. All other functions get called in a chain-reaction like way.

The constructor looks like this:

The first line is just a simple trace of a stupid message, which you should probably ignore. I always start my programs with pointless trace, because when the message appears in the output, i will know that my program compiled without any errors.

So apart from that there isn't much happening in the constructor. The second line calls the init function which is the actual constructor. Pulling all the code out of the constructor and putting it in a different function, can prove handy when you want to reïnitialize your whole movie or scene, and let the user start interacting from scratch. For instance when he pushes the home button. So let's take a look at that init function.

With the following line, we have access to the flashvars:

paramObject = this.root.loaderInfo.parameters;

Flashvars are variables that can be passed from the html-page to the embedded flashmovie.
This program relies on three of these variables: pictureWidth, pictureHeight and locationXML. That last one will be discussed later on. The other two are the dimensions of the picturepanels.

Because we also want to be able to test the movie offline, we will have to let actionscript check if they have been set or not, and if necessary assign a default value to them or in this case keep the old value. We can do this with a syntax that looks a bit like this:

variable3 = (boolean_expression) ? variable1 : variable2 ;

For a long time i coded stuff like this with an if(...){...}else{...} statement. This is kind of the same, only you can do the same thing in one line of code. So in our code it will look like this:

pictureWidth = (paramObject['pictureWidth']) ? paramObject['pictureWidth'] : pictureWidth;

pictureHeight = (paramObject['pictureHeight']) ? paramObject['pictureHeight'] : pictureHeight;

For now we don't do anything with these variables and concentrate us on the last two functions, that get called at the end of the init method, which are init3Dengine and loadXML.

init3Dengine sets up all papervision3D objects (viewport, renderer, default_scene and default_camera).

loadXML initiates the loading of the XML document. The URL of the XML can be set with a flashVar and will default to data.xml. We add an event to the XMLloader, so that when the asset is available we can add our pictures to the default_scene with the init3D method.

init3D does three things. It creates the track. Then adds the Plane objects by parsing the xml and passing a path to the picturePlane method. This little method prepares the plane for us by applying the provided picture as a texture and adding the event listener so the picture can be pushed over.

The third thing init3D does is attaching the onEnterFrame event. So now our objects are ready ot be animated and pushed around.

When pushPanel is invoked it will check wether this was the last panel being pushed. If that is the case it will call an interval to raise up all pictures again and push the track backwards with upraise. If it is not the last picture, the picture will fall down and the next one will come forward by moving the track with the moveTrack function.

These two last functions tell flash what to do every frame. Adjust the rotation of the panels and distance of the track.
And also render the papervision scene.

Implementation or embedding. 

In the zip file i have included an example index.html that uses an swfobject. More information about using swfobject can be found at googlecode.
Be sure to place a div with id swfFrame in the body of your html like this:

The javascript in the header to overwrite the div with id swfFrame looks a little bit like this:

Notice the three flashVars locationXML, pictureWidth and pictureHeight. With these we can control respectivily which xml to load, how high and how wide the pictures need to be shown.

That's it there's no more to it.

Quinten Clause