ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Building a Tsunami
http://www.actionscript.org/resources/articles/150/1/Building-a-Tsunami/Page1.html
Thomas Barslund
 
By Thomas Barslund
Published on September 9, 2005
 
Tutorial details:
Written by: Thomas Barslund
Difficulty Level: advanced
Requirements: Flash 4,5
Download FLA

Page 1 of 3
Tutorial details:
Written by: Thomas Barslund
Difficulty Level: advanced
Requirements: Flash 4,5
Download FLA In order to understand the following properly, you should be well acquainted with ActionScript, since the file requires some advanced scripting knowledge.


Thanks to Joshua Davis for allowing us to duplicate his original effect from www.praystation.com in this tutorial.

The idea
The idea is to have a box, which contains a number of objects. When the cursor is located inside the box, then we want to apply a scale and alpha value to each object dependent on the distance between each object and the cursor. On the other hand, when the mouse is located outside the box, we want each object to return to its original state.

The structure
On the main stage, you’ll find a movie clip called “01 – boundingbox” and some actions in frame 1, which set the player so that the movie is always drawn at 100% and the image is never scaled, return the player to normal menu view and stop the file (this is necessary because of the comments):
[as]
FS Command ("fullscreen", "false")
FS Command ("allowscale", "false")
Stop
[/as]
Inside “01 – boundingbox” you’ll find three layers, which contain an empty movie clip, the box and our objects, which have been stored inside a movie clip named “column1”. There is only one action in frame 1, which simply makes the centre of the movie clip (“dragscale”) appear directly under the mouse pointer. This is necessary, since we want to determine the distance between the cursor and our objects:
[as]
Start Drag ("dragscale", lockcenter)
[/as]
The crucial actions are located in frame 2 inside “column1”; the action in frame 3 simply insures that the actions in frame 2 are carried out continuously:
[as]
Go to and Play (2)
[/as]
You’ll notice that there are 20 layers, where the first contains our actions and the rest our objects. Furthermore, object 1 and 19 (the first and last) are empty, which is because we do not want our objects to be scaled beyond the box. These objects have been called “text” followed the object’s number (e.g. the first is called “text1” and the last “text19”).

Initialising our environment
In frame 2, you’ll find the following actions:
[as]
Set Variable: "colnum" = 1
Set Variable: "startnum" = 1
Set Variable: "endnum" = 19
Set Variable: "numberofItems" = 19
Set Variable: "mouseposX" = Int ( GetProperty ( "../dragscale", _x ) )
Set Variable: "mouseposY" = Int ( GetProperty ( "../dragscale", _y ) )
Set Variable: "i" = startnum
Set Variable: "m" = startnum+1
Set Variable: "filledSpace" = 0
Set Variable: "gapspace" = 0
If (myInit = FALSE)
  //Comment: on first run make an array of all the text Y Pos.
  Loop While (i <= endnum)
    Set Variable: "textY" & i = GetProperty ("text" & i, _y )
    Set Variable: "i" = i + 1
  End Loop
  Set Variable: "i" = startnum
  Set Variable: "myInit" = TRUE
End If
Set Variable: "boundleft" = GetProperty ("../boundbox" & colnum, _x)
Set Variable: "boundright" = boundleft + GetProperty ("../boundbox" & colnum, _width)
Set Variable: "boundtop" = GetProperty ("../boundbox" & colnum, _y)
Set Variable: "boundbottom" = boundtop + GetProperty ("../boundbox" & colnum,_height)
[/as]
The first variable is simply the number of the box. In this case, we’re located inside box no. 1 (“column1”). The next three variables are the starting and ending number and the number of objects ("startnum", "endnum" and "numberofItems"). We then determine the coordinates of the mouse by storing them in the next two variables "mouseposX" and "mouseposY". Furthermore, we need counters for the loops, which are called "i" and "m". Finally, we reset two variables, "filledSpace" and "gapSpace", which will be discussed later in this document.

Since we want our objects to have an original position, we need to make an array, which holds these values. When we have stored an original vertical position for each object, we reset "i" for further usage and ensure that these actions will only be performed the first time, by setting "myInit" to true (the actions are only carried out, if "myInit" is false). As mentioned, we only want to apply a scale and alpha value to each object, if the mouse is located inside the box and thus we need to know the borders, which the next four variables take care of ("boundleft", "boundright", "boundtop" and "boundbottom").

After we have initialised our environment, we have two cases, where mouse is located either inside the box or outside the box.

Page 2 of 3

Building a Tsunami
In the first case, we have the following code:
[as]
If (mouseposX >= boundleft and mouseposX <= boundright and mouseposY >= boundtop and mouseposY <= boundbottom)
  Loop While (i <= endnum)
    Set Variable: "myDif" = (EVAL("textY" & i) ) - (mouseposY-boundtop)
    //Comment: percentage increase
    Set Variable: "scaleAmount" = 250 - ((myDif*myDif) /16)
    Set Variable: "alphaAmount" = 100 - ((myDif*myDif) / 6)
    If (scaleAmount < 100)
        Set Variable: "scaleAmount" = 100
    End If
    If (alphaAmount < 50)
        Set Variable: "alphaAmount" = 50
    End If
    Set Property ("text" & i, X Scale) = scaleAmount
    Set Property ("text" & i, Y Scale) = scaleAmount
    Set Property ("text" & i, Alpha) = alphaAmount
    Set Variable: "i" = i + 1
  End Loop
  //Comment: *** add up total Y space filled by text ***
  Loop While (m <= endnum - 1)
    Set Variable: "filledSpace" = filledSpace + GetProperty ( "text" & m, _height)
    Set Variable: "m" = m + 1
  End Loop
  //Comment: *** find total Y space not filled by text***
  Set Variable: "totalheight" = GetProperty ( "text" & endnum, _y) - GetProperty ( "text" & startnum, _y)
  Set Variable: "gapSpace" = totalheight - filledSpace
  Set Variable: "avgDistance" = gapSpace / numberofitems
  Set Variable: "m" = startnum + 1
  Loop While (m <= endnum - 1)
    Set Property ("text" & m, Y Position) = (GetProperty ( "text" & (m-1), _y) + GetProperty ( "text" & (m-1), _height)) +   avgdistance
    Set Variable: "m" = m + 1
  End Loop
[/as]
The first If statement confirms that the mouse is located inside the box. If it is, then we need to calculate the distance between each object and the cursor. This is done in a loop, where we first determine the distance between the mouse and the top bound. This is necessary, since the object and the mouse aren’t located in the same level (it would only be indifferent, if the top bound was 0). The distance between the object and the mouse is then the object’s vertical position minus the value, we just calculated (the parenthesis).

After we have calculated the distance between the object and the mouse, we want to use this value (“myDif”) to determine the scale and alpha value of the object. The way these values are determined is similar and also very important. If you look at the variable “scaleAmount”, then you’ll notice that it is dependent of “myDif”. If “myDif” equals 0, then “scaleAmount” would be 250 (maximum). If “myDif” is greater, then “scaleAmount” would be smaller and thus a greater distance results in a smaller scale. Since “myDif” is squared, we accomplish symmetry around the location of the mouse. An example of this would be to have two objects, where “myDif” equals –5 and 5. These objects would have the same scale, since (-5)*(-5) = 25 and 5*5 = 25. If “myDif” wasn’t squared, but only divided by 16 (if you increase this number, this will result in a larger scale and an expansion of the tsunami), then another If statement converting “myDif” to an absolute value would be required. Furthermore, a relative small distance would give a relative large scale, which wouldn’t look satisfying. To ensure that an object isn’t smaller than at first (100), we insert an If statement. The alpha value is calculated in exactly the same way; the only difference is that the maximum is 100; the minimum 50 and we divide by 16 instead of 250, 100 and 6 (_xscale and _yscale are measured in percentages with the default set to 100). We then apply these values by using Set Property.

Finally, we want the distance between the objects, when the mouse is located inside the box, to be the same. In order to do this, we need to calculate an average distance between the objects. For this purpose, we need to find the space filled by the objects (“filledSpace”), which is the sum of all the heights (except for the first and last, since they are empty), and the total space between the first and last object (“totalheight”). The space not filled by the object is then the total height minus the filled space (“gapSpace”). To find the average, we divide this variable by the total number of objects (“avgDistance”). Having calculated the average distance, we want to apply this value to each object by using Set Property (this is not done for the first and last object, since these are empty movie clips and thus our starting value in the loop is the first object plus one. We loop while this starting value is smaller or equal to the ending value, which is the last item minus one). When applying the value, the object is placed according to the position and height of the previous movie clip plus the average distance.

Page 3 of 3

Returning to the original state
In the second case, we have the following code:
[as]
Else
    Comment: *** shrink text back when mouse rolls out
    Set Variable: "i" = startnum
    Loop While (i <= endnum)
        If (int ( GetProperty ("text" & i, _yscale ) ) > 100)
            //Comment: return scale back to original state
            Set Property ("text" & i, Y Scale) = Int ( GetProperty ("text" & i, _yscale ) ) - 1
            Set Property ("text" & i, X Scale) = Int ( GetProperty ("text" & i, _xscale ) ) -1
        End If
        If ( GetProperty ("text" & i, _y) < EVAL("textY" & i))
            //Comment: return y position back to original state
            Set Property ("text" & i, Y Position) = Int ( GetProperty ("text" & i, _y ) ) + 1
        End If
        If ( GetProperty ("text" & i, _y) > EVAL("textY" & i))
            Set Property ("text" & i, Y Position) = Int ( GetProperty ("text" & i, _y ) ) - 1
        End If
        If ( GetProperty ("text" & i, _Alpha) > 50)
            Set Property ("text" & i, Alpha) = Int ( GetProperty ("text" & i, _alpha ) ) - 1
        End If
        Set Variable: "i" = i + 1
    End Loop
End If
[/as]
The first Else statement confirms that the mouse isn’t located inside the box and thus we want to return all objects to their original state. If this is the case, then we have to take in account, if an object has a greater scale or alpha value than its original and if the vertical position is greater or smaller than the original, which is done in a loop. If the scale is greater than the original (100), we decrease the scale by –1. If the alpha value is greater than 50, we decrease it by –1 in the same way as with the scale. If the vertical position is greater than the original, we decrease it by –1 and on the other hand, if the vertical position is smaller than the original, we increase it by 1.

Customizing the file
To create multiple columns, you will need to add additional bounding boxes inside “01 – boundingbox”. The second box must be called “boundbox2”, the third “boundbox3” etc. When this is done, the columns must be placed inside the appropriate box and the first four variables in frame 2 inside the columns changed according to the number of the box, starting number, ending number and number of objects. For example the second column (inside box no. 2) should have the column number 2 (if it was 1, then the objects would be scaled and given an alpha value, if the mouse was located inside box 1). The scale amount and alpha value could be specific to each column; you would only have to change the maximum, minimum and dividend in “scaleAmount” and “alphaAmount”.