Since my retirement from teaching in 2007, I have been writing a blog that includes flash animations on the physics of waves and resonances. As a physicist, I have programmed many different computers over the years in various languages. At the same time I am not a professional programmer. The last few months represent my first foray into Flash and Actionscript. Primarily because of cost, I have used Swish Max and found it to work well for my purposes. You can view my physics animations at http://resonanceswavesandfields.blogspot.com/. In the posting below, I will discuss a few ways I have discovered to animate wave motion in flash.

### 1. Dragging a long wave image repeatedly across the scene

In this first method, one simply draws a long banner-like object containing a number of complete cycles of the wave. The banner is somewhat wider than the scene (or wider than a mask if you wish to go that route). Then playing with the time line, one makes this wave slide in the desired direction, exactly one wavelength in the number of frames allotted. At the end of these frames, the wave is reset to its original position and the cycle is repeated, again and again. When it is played, the viewer sees a myopic view, and in this view, the wave seems to slide in the desired direction forever. The viewer is not aware that the wave really only slides one wavelength and is then abruptly restarted at its original position to repeat the process. Some tips on doing the above are:

- To make the wave, first draw one wavelength only. Then set "snap to grid" and "show grid". This allows you to copy the one wavelength repeatedly and position the copies to line up perfectly. You can add anything you want in front of the wave or behind it. I show a mermaid and the sun.
- A real challenge of this method is to make sure, at the last frame, the wave has moved exactly one wave length over and hasn't changed height. You will notice a slight flicker in my rendition due to my less-than-perfect alignment.
- A real plus of this method is that you can make the wave as complex or artistic as you want.
- Another feature is that this method uses no programming (or "script" as SwishMax calls it).

In the first animation below I show the wave without the required undersized scene1 boundaries, so you can see what is happening. In that, I show a rectangle representing the stage edges or mask size. The second animation shows the myopic effect with a properly undersized scene or mask. Mouse over the animations to see the action.

#### What the programmer sees:

#### What the viewer sees:

In order to allow the viewer to stop the action, I added the following script to scene1:

onSelfEvent(load){stop( )}

onSelfEvent(rollOver){gotoAndPlay(1);}

onSelfEvent(rollOut){stop( )}

#### Another example, this one showing a surface wave:

Carrying this idea to the next level, below we have a two dimensional wave done with this method. This might represent an aerial view of ocean waves, looking down at the ocean from an airplane, for example. To help with moving one exact wave length, I added two guide lines as seen in the first of the two animations below.

The actual waves were made, by first drawing a rectangle one half wavelength wide, using gradient fill to make it colored from blue to white. The outline was turned off. This rectangle was then copied, flipped, and positioned up beside the first one (having the snap on helped all these operations). Then the set of two rectangles was copied repeatedly and lined up to complete the long set of waves. The completed wave banner was then rotated. It was made to move one exact wavelength in 30 frames.

#### What the programmer sees:

#### What the viewer sees:

The above method is quite flexible. One could skew the wave field above and move it across the scene. One might also add ripples to the top of the waves. Or he could make the wave segments be trapezoidal and instead of sliding the wave field, he could rotate it about a somewhat removed center. This would give the illusion of a perspective view of the waves.

### 2. Waves by equation

Another way to create a wave in flash is by using an equation for it and drawing a curve to that equation. Of course this is a scientist's, engineer's, or mathematician's method of choice. Most of the waves in my blog are done using this method. And it certainly requires some programming, but not very involved programming.

The basics parts to the program are:

- We need to draw the scene: a foreground, a blank invisible rectangle as a "container" for the wave layer (check the container as a "target"), and a background. If you need only the wave, forget this step. On the other hand, having a container makes getting the layering (or "depth") easy so that you can have other objects in the scene in front of and behind the waves. Be sure not to stretch the container or all coordinates in it will be stretched. I set the container's origin to equal scene 1's origin to keep the coordinates simple.
- Similar to the previous program, I have the animation set to only operate if the viewer mouses over the animation and it stops when the mouse leaves the animation. This avoids having the animation run when the viewer is not looking at that page. To achieve this, on load, the first graph is drawn, then in Frame 1 there is a stop. When the viewer mouses over the animation, the program starts on Frame 2, where it draws the second graph, proceeds to Frame 3 which adds to theta and returns the program to Frame 2 to redraw the graph with the larger theta. It continues on this cycle until the user mouses off the animation. The ever increasing theta makes the waves progress with time, provided we use the correct equation.
- If you have questions on the specific steps, go to the Swish Max user's guide and search on the instruction of interest. The steps for producing the filled wave shape are shown under the "beginFill" instruction.
- Basically, this program redraws the wave every cycle through the program. It uses the standard equation for a traveling wave of
*y*=*A*cos (*kx*−*ωt*) . If you would like to read more about the equation you might read my blog on the subject or other sources like Wikipedia. - The advantages of this method is that it can graph equations and produce waves as specified by equations. Thus, in some sense, it is very flexible. Any wave that has a nice mathematical formula can be animated with this method. For example, with a little augmentation of the program below, we can produce waves on a mesh surface. These can include both linearly and radially propagating waves. Examples of these are at http://resonanceswavesandfields.blogspot.com/.
- The disadvantage of this method is that it requires programming, it is hard to create "artistic" waves, and while the flash program size is tiny (no bit maps) it can be very computationally intensive and slow on slow computers.
- The script and the actual animation are shown below.

#### The animation:

Mouse over it to see the action.#### The script:

onSelfEvent(load){ var theta:Number=0; // initial value of omega x time. const xmax:Number=Stage.width; const N:Number=xmax/dx; const y1:Number=Stage.height; const y0:Number=220; drawGraph(); }// end of load onSelfEvent(rollOver){gotoAndPlay(2);} onSelfEvent(rollOut){stop()} function drawGraph(){ container.clear(); container.lineStyle(1,0x000000,100); container.beginFill(0x0000FF,100); container.moveTo(0,y1); var x:Number=0; for(var i:Number=0;i<N;i++){ var y:Number=y0-15*Math.cosdeg(1.1*x-theta); container.lineTo(x,y); x+=15; }// end of i loop container.lineTo(x-dx,y1); container.lineTo(x,y1); container.endFill(); } // end of function drawGraph onFrame(1){ stop() } onFrame(2){ drawGraph(); } onFrame(3){ theta+=15; gotoAndPlay(2) } onFrame(4){ stop() } |

### 3. Waves by shifting values through an array

This method is similar to the last one, in that we use an equation to produce the wave height, and we redraw the wave each cycle, but to reduce computation time, we save the values from previous computations and shift them through an array. Each time through Frame 2, the program calculates a single new value to push into the array. It then, in one loop (in the drawGraph function), simultaneously plots the points in the array and shifts the array values over by one.

#### The animation:

Mouse over it to see the action.#### The script:

onSelfEvent(load){ y=new Array; // array to store y values of the wave var theta:Number=0; // initial value of omega x time in units of degrees const dtheta:Number=20; const dx:Number=6; // the spacing of plotted points in pixels const k:Number=dtheta/dx; // the wavenumber in degrees per pixel const xmax:Number=Stage.width; const N:Number=xmax/dx; const y1:Number=Stage.height; // base of the filled area in pixels const y0:Number=220; // average height of the wave in pixels fillArray(theta); drawGraph(); }// end of load onSelfEvent(rollOver){gotoAndPlay(2);} onSelfEvent(rollOut){stop()} function waveValue(x,theta){ return y0-15*Math.cosdeg(k*x-theta); } function fillArray(theta){ for(var i:Number=0;i<N;i++){ y[i]=waveValue(i*dx,theta); }// end of i loop }// end of function fill Array function drawGraph(){ container.clear(); container.lineStyle(1,0x000000,100); container.beginFill(0x0099FF,80); container.moveTo(0,y1); var x:Number=0; var ynow:Number=waveValue(0,theta); for(var i:Number=0;i<=N;i++){ container.lineTo(x,ynow); var ytemp:Number=ynow; ynow=y[i]; y[i]=ytemp; x+=dx; }// end of i loop container.lineTo(x-dx,y1); container.lineTo(x,y1); container.endFill(); }// end of function drawGraph onFrame(1){stop()} onFrame(2){ theta+=dtheta; drawGraph(); } onFrame(3){ gotoAndPlay(2) } onFrame(4){ stop() } |

### 4. Waves by difference equation

While the previous three methods assume that waves are repeating functions that move at a constant speed, this last method uses a finite difference approach to actually solve the wave equation

where *c* is the speed of the wave. This method operates on an array of *x* and *y* values. The *x* values are not actually stored as an array, but instead are calculated as needed, assuming they occur at regular intervals, i.e. *x*_{i+1} = *x*_{i} + *dx*, where *dx* is constant. In contrast, the *y* are stored in an array, similar to that used in the previous example. The *x* and *y* values are used to draw the wave each cycle in the program.

In order to model a wave that is changing with time, we need an equation to tell us how much each *y* changes each cycle. This can be gotten from the wave equation above. We can rearrange the equation to solve for the time derivate term, the second term above, as

where we have also shown alternate styles of writing the time derivate term. Now, changing from a continuous derivative to a difference notation (required for actual computation), we rewrite this equation as:

.

In the right most term, we have changed the *x* derivate into its difference counterpart, i.e.:

This equation requires the knowledge of *y* values on either side of a particular array element to calculate the next value of that element. It works for all the elements, except for the two end point *y* values that do not have element on both their sides. Thus we need to treat the end values specially. I decided to let
the left end point be driven in a sinusoidal pattern, assuming that this is the source of the waves. The right
most point is harder. Unless it is treated properly the waves will reflect and mix with the oncoming waves. (Yes, these equations embody the physics of waves and will demonstrate reflections if so allowed.)
Avoiding this requires that the motion of the right end point is damped with damping coefficient *D*. I experimented with various values of *D* until the reflections were absent. The equation for this right most element is

.

These equations have be incorporated in the following animation.

#### The animation:

Mouse over it to see the action.#### The script:

onSelfEvent(load){ y=new Array; // array to store y values of the wave vy=new Array; // to store velocities of y values var theta:Number=0; // initial value of omega x time in units of degrees const dtheta:Number=20; const dx:Number=12; // the spacing of plotted points in pixels const invM:Number=1; // inverse mass in 1/(framesSquared). Program unstable if this is > 1.0 . const damp:Number=1.0 // damping coefficient of the right most element const xmax:Number=Stage.width; const N:Number=Math.floor(xmax/dx); const y1:Number=Stage.height; // base of the filled area in pixels const y0:Number=220; // average height of the wave in pixels fillArray(); // call of the function defined below drawGraph(); // call of the function defined below }// end of load onSelfEvent(rollOver){gotoAndPlay(2);} onSelfEvent(rollOut){stop()} function fillArray(){ for(var i:Number=0;i<=N;i++){ y[i]=y0; vy[i]=0; } // end of i loop } // end of function fill Array function drawGraph(){ container.clear(); container.lineStyle(1,0x000000,100); container.beginFill(0x0099FF,80); container.moveTo(0,y1); var x:Number=0; for(var i:Number=0;i<=N;i++){ container.lineTo(x,y[i]); x+=dx;} container.lineTo(x-dx,y1); container.lineTo(x,y1); container.endFill(); } // end of function drawGraph function updateArray(){ y[0]=y0-15*Math.sindeg(theta); // the left element is driven for(var i:Number=1;i<N;i++){ // update the velocities of the elements vy[i]+=invM*(y[i+1]+y[i-1] -2*y[i]); }// end of i loop vy[N]+=invM*(y[N-1]-y[N])-damp*vy[N]; for(i=1;i<=N;i++){ // now update the positions y[i]+=vy[i]; }// end of i loop }// end of function updateArray onFrame(1){stop()} onFrame(2){ theta+=dtheta; drawGraph(); updateArray(); }// end of onFrame1 onFrame(3){ gotoAndPlay(2)} onFrame(4){stop()} |