Circular Menu: Sine, Cosine, and Other Math in Flash MX

Firstly, if I were you, I would go and download the source files (they are in Flash 6, a.k.a. Flash MX, compatible with Flash MX 2004), although they are not necessary for this tutorial. Now let's go through this thing together.

First, create a new Flash document that is 600 x 300 pixels. Now, create 2 layers (one should already be there). Name them "buttons" and "actions" and it does not matter which one is on top.

Now, create 8 buttons that are about 50 to 60 pixels square. Give them all variable names (located normally in the properties window) that are the same as their current name, although it doesn't matter, just makes things a bit easier. I named mine "pic1", "pic2" ... "pic8". Make sure that they are on the "buttons" layer and that their variable names have a number in them, like mine.

Now, create an empty movie clip called "anchor" (or whatever you want, its name will not appear in any code) and place it in the center of the main timeline on the "actions" layer. Now, open up the actions box for the "anchor" movie clip. Place the following code into the box:

`onClipEvent (load) {`

for (var i = 0; i<=8; i++) {

_parent["pic"+i]._x = Math.cos(Math.PI*(i+1)/4)*135+300;

_parent["pic"+i]._y = Math.sin(Math.PI*(i+1)/4)*-135+150;

}

var end = 1;

}

This code places our buttons in a circle around the center of the movie upon the loading of the "anchor" movie clip. It does this using the sine and cosine values assigned to their _y and _x values respectively.

`for (var i = 0; i<=8; i++) {`

_parent["pic"+i]._x = Math.cos(Math.PI*(i+1)/4)*135+300;

_parent["pic"+i]._y = Math.sin(Math.PI*(i+1)/4)*-135+150;

}

The first thing that you may notice is that I used _parent instead of _root (if you are experienced in actionscripting). I prefer to use _parent because it refers to the actual timeline that the code is placed on, whereas _root refers to the main timeline. This allows us to just slap this entire flash program directly onto another flash program, in the form of a new movie clip. _root still has its uses, but I find _parent to be more flexible.

Next, you will notice the information in the brackets ( these []). This refers to the individual buttons' variable names via the first line of code. What is happening is that Flash is now creating a new variable, affectionately named "i". "i" is assigned the value of all of the numbers 0 to 8, but is only one of these each time Flash runs through the code (fortunately, Flash does this until it gets all the way to 8). Since there is no button named "pic1.5", Flash goes directly to the numbers applicable (i.e. 1, 2, 3, ... 8). ._x and ._y refer to the x-positions and y-positions of each of the buttons when they are called by Flash.

Now for the tricky part. If you have taken any trigonometry classes, you might know why I chose cosine and sine (abbreviated it code as .cos and .sin). In the circle, if you were to take the cosine value of an angle and multiply it by the radius of the circle (in our case 135), you would get the x-coordinate for the point that that angle leads to. The same is with sine, except with the y-coordinate. You may also notice, that I did not use degrees. I have used a trigonometric measurement for an angle called radians. There are 2 PI radians in a circle, which means that if you multiplied PI (approximately 3.14) by 2, you would get the degree measurement of a circle, in radians. Flash only calculates in radians, so this is very useful information. If you want to find the radians of an angle use this formula:

Radians = Angle * Math.PI / 180;

Now you will also notice that I put our little variable "i" into the equation as well. Remember how a circle is made up of 2 PI radians? Well that means that if I were to divide the circle into one eighth, then the angle of the portion (which is 45 degrees by normal standards) would be PI * 1/4. In order to give each button a different position on the circle, we would use the PI * (i+1)/4, so that it would start out with "pic1" at the top of our circle of buttons. You will also notice that the cosine value is multiplied by 135, whereas the sine value is multiplied by -135. This is because the y-axis is flipped in flash, so that as you go farther down, your y-position increases. We also add 300 to the cosine value and 150 to the sine value. This positions our entire circle in the middle of the movie. You will have finally noticed our creation of a separate variable, called "end". Right now, we want "end" to equal 1. This will be explained later.

Now for the scripted movement. Please input the following code below the last lines of code in our "anchor" movie clip.

`onClipEvent (enterFrame) {`

for (var i = 0; i<=8; i++) {

_parent["pic"+i]._x += ((Math.cos(Math.PI*(i+end)/4)*135+300)-_parent["pic"+i]._x)/5;

_parent["pic"+i]._y += ((Math.sin(Math.PI*(i+end)/4)*-135+150)-_parent["pic"+i]._y)/5;

}

}

onClipEvent (enterFrame) {

_parent["pic1"].onRelease = function() {

end = 1;

};

_parent["pic2"].onRelease = function() {

end = 0;

};

_parent["pic3"].onRelease = function() {

end = -1;

};

_parent["pic4"].onRelease = function() {

end = -2;

};

_parent["pic5"].onRelease = function() {

end = -3;

};

_parent["pic6"].onRelease = function() {

end = -4;

};

_parent["pic7"].onRelease = function() {

end = -5;

};

_parent["pic8"].onRelease = function() {

end = -6;

};

}

The first lines of code do almost the same thing as the first lines of code that we put into our "anchor" movie clip, except these tell flash how much the _x and _y values of our buttons are to increase.

The key variable here (other than our lovely "i") is the variable "end". You will have noticed that earlier on, we created the variable "end" and gave it the value 1. Because its code was initiated when the movie clip was first loaded onto the timeline, it won't stay 1. This is very important because we want each button, upon click, to move to the top of our circle of fun. The only way to do that, is to change "end". Right now, however, "end" equals 1. Because of that, there will be no increase or decrease in our _x and _y values yet. This is because the increase in _x and _y values is set to equal the new _x and _y value minus their current _x and _y values. As soon as the buttons reach their destination, both will be equal, making their increase in _x and _y equal to 0. I am dividing the resulting value by 5, to help slow down their movement. The smaller the value here, the faster they would move.

During our second onClipEvent(enterFrame) code section, we assign the buttons their tasks for when they are clicked. You may be familiar with the on(release) code, but that won't work with us, since variables, like "end", don't carry to other sections of code. This means that we would not be able to alter the value of end from the buttons' actions boxes. This is solved by the code _parent["pic1"].onRelease = function () {. This allows us to tell Flash that, when so-and-so button is clicked, it is supposed to perform these functions. This is very useful if you call the button onto the timeline using actionscript, but that won't be discussed here.

You will also notice that for each button, upon click, our variable "end" receives a new value between 1 and -6. This is because, in our equations, in order to cause a button to be at the top of the circle, end must change so that each button's radian value would change according to where they need to be. For instance, if "end" equals 4, then the code

`_parent["pic"+i]._x += ((Math.cos(Math.PI*(i+end)/4)*135+300)-_parent["pic"+i]._x)/5;`

becomes

`_parent["pic"+i]._x += ((Math.cos(Math.PI*(i+4)/4)*135+300)-_parent["pic"+i]._x)/5;`

which means that for "pic1", this would become

`_parent["pic1"]._x += ((Math.cos(Math.PI*(1+4)/4)*135+300)-_parent["pic"+i]._x)/5;`

changing its position on the circle (via a straight line, have not been able to fix that as of yet) to where it now needs to be in order to complete the circle.

And we are done! I hope that this tutorial leads you to further experimentation in the wonderful world of Flash.

Contact: ABS Forums or email at i.be.doh32@gmail.com (try the Forums first, PM me)

Credits: Actionscript.org's tutorials in general (help with Flash); Kirupa.com's tutorials in general (help with Flash); Flash Math Creativity by Manny Tan, Keith Peters, Jamie Macdonald, Glen Rhodes, David Hirmes, Lifaros, Brandon Williams, Kip Parker, Paul Prudence, Gabriel Mulzer, Jared Tarbell, Ty Lettau, Pavel Kaluzhny, Ken Jokol, and JD Hooge, for the basic flash math principles; Special thanks for the guys at the ABS forums, encouraged me to make this tutorial.