Creating a Scrolling Interface using Adobe Flash ActionScript 2.0

I've created a special video version of this tutorial so if you're interested in scrolling navigational interfaces, make sure you check this out.

I use these often in some of my pieces such as this Weapons of War project:


This was a perfect candidate for this kind of navigation because I had to present a large group of items in a short space.

Before we get started on the Flash itself, let me walk you through the process of developing one of these pieces.

Let's take a look at the soldier piece and go through what it takes to do one of these. The first step is coming up with the idea. I started this piece during the war. It was based on a layout that our sister paper in Fort Lauderdale ran.


Here's another more complicated project that uses the same concept. You'll notice this one uses changes the _alpha property of the image depending on how close the mouse is to the photo.

I tried changing the size of each image as it got close to the mouse, but it didn't work as well for this subject matter.

The piece we'll be working on today is a simplified version.Our final piece will look like this:

Our first job here would be to import the interface, which I drew in Fireworks as well as to import the thumbnails I want to use. To do this, you can simply copy and paste the interface elements from Fireworks, and then drag and drop the thumbnails into your flash document. Once you've done this, you might notice that some of these items look a little blurred, this is because the default import for Flash has smoothing turned on. We'll have to go into each bitmap and change this.

I'm going to put all my bitmaps into a library folder to get them out of the way as well. I also need to organize this file and put everything into layers so it's more comfortable to work with. At this point, I'll start this off, and then move to a file where the organization has been completed so you don't have to watch me do this.

You'll notice a couple of things on the organized file. Every main item is on it's own layer, so that I can animate it and deal with it individually. I separated the white background from the keyline putting them on separate layers. This makes sure that they keyline is always at the top of everything and the white background is behind almost everything except the top header tab and the bottom ornamental tab. because normally those would slide in when animating this interface appearance.

There is also a mask that mask the screenshots, the red triangle, the background color and the name of the device, That's because if any of those items hits the edge of the Flash piece I want them to be hidden.

Creating Symbols

Animation in flash is done one of two ways, by hand or programmatically, each with it's own advantages and disadvantages. What we'll need to do is program the screenshots to move according to where the mouse is on the screen.

Whenever you want to move an item on the screen, you'll need to create a movie symbol so that everything knows how to move together as a unit. We will need to make symbols out of all the individual items. So make sure you click on each bitmap and use INSERT:CONVERT TO SYMBOL. Once all of your individual bitmaps are symbols, I'll need to combine them into a movie symbol.

Shift-click each of the movie clips to select all of them at once, then select INSERT:CONVERT TO SYMBOL
Once I have that done, I can start animating programmatically.

Starting to animate

Whenever you want to move a movie clip symbol, you'll need to use actionscript. Every movie can have it's own actionscript and what we want to do is to put in a piece of actionscript in this movie that tells it to move. Let's see one way we can do that.

I'm going to make sure my new movie clip is selected and I'll hit the actionscript button (on the properties palette) and type in the following:

onClipEvent (enterFrame)
{
_x=_x+1;
}

What this is telling Flash to do is every time this movie clip enters a frame move it one pixel to the right. For this movie, the frame rate is set to 20 frames per second so this thing should be moving 20 pixels every second.

This can also be written like this:

onClipEvent (enterFrame)
{
_x++;
}

Or like this:

onClipEvent (enterFrame)
{
_x+=1;
}

The first version always ads one to the X position of the piece. The second one adds whatever is after the = sign to the X position of the piece. So to make it go faster you could do:

onClipEvent (enterFrame)
{
_x+=5;
}

This is cute, but you see we have absolutely no control over the movement of the movie. To do that, we'll need to know where the mouse is. You can find out where the mouse is with a special property called _xmouse.
To take a look at what the position of the mouse is at different times we're going to use a special function called trace();. It gives us some feedback in a special window when we're testing movies. Every time the movie enters a frame I'm going to put the value of _xmouse in that special window. Rewrite the code like this;

onClipEvent (enterFrame)
{
_x+=1;
trace(_xmouse);
}

Alright, if you look carefully, you'll notice a few things. as you move the mouse around the value of xmouse gets bigger and smaller. But if you leave the mouse standing still, you'll realize the value of xmouse keeps changing. Why is it changing. It's because the value of _xmouse is relative to the current movie, because we're moving the location of this movie about 20 frames per second, the value of _xmouse will change that much. This is no good. We need a value of the mouse that is independent of the movie. So change the above to this:

onClipEvent (enterFrame)
{
_x+=1;
trace(_root._xmouse);
}

Ok, now the value of _xmouse only changes when I move the mouse because I'm checking the position of the mouse relative to the main movie (called _root). I'm noticing that the midpoint position of the mouse is at about 340 pixels to the right of the beginning of the movie (it's about half the size of the movie), so if I could find out when the user puts the mouse to the right of that, I could make the movie move to the right, and when the user puts the mouse to the left of that, I can move the movie to the left. That's easily done with some if then statements. It looks like this:

onClipEvent (enterFrame)
{
if (_root._xmouse>340)
{
_x++;
}
else
{
_x--;
}
}

Actually, the reverse of that works much better, because we're trying to get things to move towards us so we'll change that to this:

onClipEvent (enterFrame)
{
if (_root._xmouse>340)
{
_x--;
}
else
{
_x++;
}
}

That's better, but it's moving at warp 1, let's bump it up to warp 5;

onClipEvent (enterFrame)
{
if (_root._xmouse>340)
{
_x-=5;
}
else
{
_x+=5;
}
}

Alright, that's cute, but something is bothering me here. It was kind of hard to figure out where the center of the movie was, and also remember that we might be using this piece as part of a bigger flash piece, so the center of this scroller might even be off to one side.

To do this, we can create a new movie clip and put it wherever we want the center to be, then compare the position of the mouse with the position of this movie clip.

You can easily make a movie clip by drawing a square, selecting it and then going to the INSERT menu and selecting CONVERT TO MOVIE CLIP. Now put this movie clip where you want the center of the movie to be. Now we want the movie clip that moves to find out what the position of this movie clip is. In order to do that we'll need to name this clip. This is called giving the movie clip an instance name. You can do that in the properties palette. I'm going to call this one "center".

Ok, now I can re-write my script like this:

onClipEvent (enterFrame)
{
if (_root._xmouse>_root.center._x)
{
_x-=5;
}
else
{
_x+=5;
}
}

If you move the square around, you'll see that the position where the movie changes direction changes.
Ok, that works just as well as the previous example, but now we have this gray square in the middle of the movie. No good. we need to hide it. You'll need to tell the "center" movie clip to hide itself before anyone sees it. We can do that by writing this actionscript in the "center" movie clip:

onClipEvent(load)
{
_visible=false;
}

Alright, that takes care of that. My next pet peeve with this project is that the scrolling is constant and the change between the movement from one side to the other one is very abrupt. I would like this to move quicker when I move the mouse farther to the left and slow down the movement as I move to the right like in some of my pieces. What I need to know is the difference between the center of the movie and the mouse position. If the difference is great, then move faster, if the difference is small, move slower.
Click on the movie clip with all the bitmaps and change the script to this:

onClipEvent (enterFrame)
{
difference=_root.center._x-_root._xmouse;
_x+=difference;
}

Alright, notice two things when you try this. First we got rid of the whole if then set of statements. That's because the difference will be a negative or a positive number automatically depending on where my mouse is, so the if else statement is no longer needed. The second thing you'll notice is that this thing moves faster than a jackrabbit. We'll need to slow it down. We can do that with another if then statement. Something like this:

onClipEvent (enterFrame)
{
difference=_root.center._x-_root._xmouse;

if (difference>20)
{
difference=20;
}

if (difference<-20)
{
difference=-20;
}
_x+=difference;
}

That works ok, but I want this to have a smooth flowing motion like an ice skater, so that when the user switched directions, there's a little bit of a reactionary delay in the interface. For this we'll need to apply a little friction to the formula.

onClipEvent (enterFrame)
{
difference=_root.center._x-_root._xmouse;
_x+=difference*.20;
}

The .20 above acts as a friction and allows your navigation to flow a lot smoother with a lot less coding.

Making it repeat

You might have noticed, this thing keeps moving even if there's no more movie to see. What I want it to do is to repeat itself or at least look like it's repeating itself every time the user gets to the end of a set. I don't want to fool with duplicating movie clips, because that's too complicated, what I'll do is triplicate my movie clip and then use and optical illusion to make users think that it's endless.

Alright, this might get tricky. Remember we have one movie clip inside the main movie clip. What we're going to need is to create a movie clip that has three movie clips inside it. We'll first need to get into the movie clip with all the bitmaps, then make a new movie clip out of the contents there and triplicate them.Okay, double click on the movie clip with all the bitmaps. Notice the path under the main timeline should say something like SCENE 1: ALL BITMAPS and the background should be grayed out. Now, select all the bitmaps there and choose CONVERT TO SYMBOL from the INSERT menu.

Alright, we've got one made, now we need to duplicate that clip and put it to each side of the current piece.
Once you've done that click on the SCENE 1 link underneath the timeline and preview the movie.
Now all we have to do is change the code so that it resets the position of this triple movie clip to the original position that it was when it got started.

The code looks like this:

onClipEvent (load)
{
onepiecewidth=_width/3; //figure out the width of one piece
originalx=_x; // find out where the original value of the piece was
}

onClipEvent (enterFrame)
{
difference=_root.center._x-_root._xmouse;
_x+=difference*.20;
if ( (_x >= (originalx+onepiecewidth)) || (_x <= (originalx-onepiecewidth)) )
{
_x=originalx;
}
}

Note I'm saving the width of the single piece and the original position of this movie clip so that when the position of this piece moves one width in either way, the position gets reset to it's original, causing the optical illusion that this thing goes on forever.

Polishing the interface

The next step is to get the remainder interface elements to work. Let's take care of the triangle because it's the easiest one to do.

We need to make the movement of the triangle match the movement of the mouse. First, we'll need to make the triangle into a movie clip. That will allow us to script it.

Next the Actionscript, it's easily done with this script which needs to be placed inside the triangle's movie clip:

onClipEvent(enterFrame)
{
_x=_root._xmouse;
}

Ok, now it's time to move the name. I can make the movement of the name follow the movement of the mouse the same way. First make it into a movie clip, then assign this script to it:

The name field might need to be centered and enlarged a little bit.

The movement of the NAME field seems a little stiff, it would be better if it moved in a similar fashion to the movie clip with a little bit of friction to is, so I'll modify the movie clip for the name with something very similar to what we've done with the scrolling movie clip.

onClipEvent(enterFrame)
{
difx=_root._xmouse-_x;
_x+=difx*.25;
}

You can have as many graphic elements on the screen, assign them different friction numbers and they will all arrive at the mouse position at slightly different times which looks neat.

Creating buttons for the icons

The next step is to convert the bitmaps to buttons so that when we put our mouse over them, they highlight.
I'm going to grab the yellow background that's behind everything and double click on the bitmap area twice. If you take a look at the hierarchy under the timeline you'll see that you're inside the movie clip with the three bitmaps and then inside the movie clip with a single set of movie clips.

Now, I'll click on any one of the individual bitmaps once, and then convert them to a button by choosing CONVERT TO SYMBOL from the INSERT menu. Make sure you choose the BUTTON symbol type. Click OK.
Now double click on the newly created button to get into the button definition. It looks similar to what's inside a normal movie clip, except for the tabs at the top. A button can only have four frames. One for what it looks like under normal circumstances, one for when the user rolls the mouse over the clip, one for when the button is pressed down and the last HIT area that defines the "HOT" area of the button. We're really only interested in the first two frames in this case, so I'm going to create a new keyframe on the OVER frame of the button.

When I do that it creates a new frame with a copy of the button already in it. Now I'm going to paste my yellow background and move it so that it looks good. Once that looks good, I can preview the image.
I need to do the same thing to all of the bitmaps, so they will all highlight when the mouse goes over them. We're almost done.

For the sake of brevity, I'm going to switch to a file that has all the buttons completed. It should be 09-ButtonsDone.fla.

Name & descriptions

The next logical thing to do is to fix this so that when you rollover one of the buttons, the information in the NAME field and the DESCRIPTION FIELD change. In order to do this we'll need to set a variable's value at the root level whenever the user rolls over on of the buttons.

If your hierarchy is back to the beginning double click on the movies with all the buttons until you get to the individual movies. I'm going to try this out in the streetball button, so find it and enter the following script.

on (rollOver)
{
_root.name="STREETBALL";
_root.description="NBA players with street ball moves";
}

That will set a variable at the root level for both the name and description. I also want to make sure that if the user clicks on the button, it goes to the URL with that piece. so I'll need to add a little more javascript to this button.

on (release)
{
getURL( "http://www.orlandosentinel.com/extras/dynamic/streetball/streetball.html") ;
}

Test this out and you'll see that when you click on the button it launches the flash file. If you want it to open in a new window so that we still have our interface, we can try this:

on (release)
{
getURL ("http://www.orlandosentinel.com/extras/dynamic/streetball/streetball.html ","_blank")
}

That's a little better, but it creates a huge window. It would be better if it created a window just the right size. You can use a little Javascript to take care of that:

on (release)
{
getURL("javascript:window.open ('http://www.orlandosentinel.com/extras/dynamic/streetball/streetball.html', 'WindowName','width=760,height=500'); void('') ")
}

Names & descriptions

Alright, now we need to fix all the NAME, DESCRIPTION and URLS before we get to changing the NAME and DESCRIPTION fields. In order to do that, we simple change text fields from static text fields to Dynamic Text fields and change the VAR box in the properties palette to the variables that we set in each of the buttons.

Adding sound

There are several ways to add sounds to your flash movie. My favorite way to do it is to do it programmatically.
First I'll need to get some sounds. I happen to have most of these flash pieces I've worked on before with imported sounds already on them, so I'm just going to open one of those and copy my sounds folder from one of the old Flash presentations to this new one.

To place sounds into flash, you'll need to save the sounds as .wav or AIFF files and put them in your hard drive, then use the FILE menu and select IMPORT to import them into your movie.

Once you've place the sounds, you're halfway there. You need to five the sounds a name that you can refer to when calling the sound programmatically. so click on a sound and from the LIBRARY palette menu select LINKAGE. Click the EXPORT FOR ACTIONSCRIPT item and give it a name under IDENTIFIER.

Now you're ready to call the sound from ActionScript. The code that I need to add to each button is as follows:

mySound=new Sound();
mySound.attachSound("windowopening2");
mySound.start(0,1);

So that your button code should look something like this:

on (rollOver)
{
_root.name = "STREETBALL";
_root.description = "NBA players with street ball moves";
mySound=new Sound();
mySound.attachSound("rollover");
mySound.start(0,1);
}

on (release)
{
getURL("javascript: window.open( 'http://www.orlandosentinel.com/extras/dynamic/streetball/streetball.html' ,'WindowName', 'width=760,height=500'); void('');")
mySound=new Sound();
mySound.attachSound("click");
mySound.start(0,1);
}


That's it, pat yourself in the back...you're done.

blog comments powered by Disqus