Tuesday, June 21, 2011

How to Make a Clock that follows the Mouse with Delay in AS3

Difficulty: Easy (but math heavy)


Skills Used: following the mouse with delay, random numbers, event handlers, addChild, getting the time


This isn't an especially useful app, but it looks cool. Every time you move the mouse, the parts of the clock follow (with delay). Every part of the clock travels at a different speed, which is randomized every time you move the mouse. And of course, it keeps perfect time.

Instructions: 
1. Open a new file in Flash. Make sure you are using Actionscript 3.0. Right click on the grey area around the stage and select "Document Properties" from the menu that pops up. I made my stage 500 x 500 pixels, you can always change this later.


2. In the top menu, select Insert -> New Symbol and name it "12". Select the Text tool from the Tool menu, it looks like the letter T. In the Properties Inspector, set the first two options to "Classic Text" and "Static Text". Then pick the font and font size that you want. Mine is "Herculanum", 35 pt. Click on the stage. Type the number "12". In the Tools window, select the Selection tool, it looks like a black arrow. Click on the "12" you typed. Use the Alignment window to center the 12 right over that little cross in the middle of your screen.


3. Repeat the last step to create movieclips for numbers 1 - 11.


4. In the library, you should now be able to see movieclips 1 - 12. We need to give each movieclip a class name so your Actionscript can read it. Doubleclick to the right of "1", under the word "Linkage". When the cursor pops up, type in "one". It's better to spell out the word, if we only use numbers it will foul up the code later. Now doubleclick to the right of "10" and type in "ten", and so on and so forth until all twelve movieclips have Linkage names.


5. Open up the Actions window and paste in the following code:


var a:Number = 32.5;
var b:Number = 56.3;
var c:Number = 65;


var myTwelve:twelve = new twelve();
addChild(myTwelve);
var random12:Number = (8 + Math.floor(Math.random()*12));//sets the initial speed of the number before the mouse moves


var myOne:one = new one();
addChild(myOne);
var random1:Number = (8 + Math.floor(Math.random()*12));


var myTwo:two = new two();
addChild(myTwo);
var random2:Number = (8 + Math.floor(Math.random()*12));


var myThree:three = new three();
addChild(myThree);
var random3:Number = (8 + Math.floor(Math.random()*12));


var myFour:four = new four();
addChild(myFour);
var random4:Number = (8 + Math.floor(Math.random()*12));


var myFive:five = new five();
addChild(myFive);
var random5:Number = (8 + Math.floor(Math.random()*12));


var mySix:six = new six();
addChild(mySix);
var random6:Number = (8 + Math.floor(Math.random()*12));


var mySeven:seven = new seven();
addChild(mySeven);
var random7:Number = (8 + Math.floor(Math.random()*12));


var myEight:eight = new eight();
addChild(myEight);
var random8:Number = (8 + Math.floor(Math.random()*12));


var myNine:nine = new nine();
addChild(myNine);
var random9:Number = (8 + Math.floor(Math.random()*12));


var myTen:ten = new ten();
addChild(myTen);
var random10:Number = (8 + Math.floor(Math.random()*12));


var myEleven:eleven = new eleven();
addChild(myEleven);
var random11:Number = (8 + Math.floor(Math.random()*12));


addEventListener(Event.ENTER_FRAME,assembleClock);


function assembleClock(event:Event)
{
myTwelve.x += (mouseX - myTwelve.x) / random12;
myTwelve.y += ((mouseY - c) - myTwelve.y) / random12;

myThree.x += ((mouseX + c) - myThree.x) / random3;
myThree.y += (mouseY - myThree.y) / random3;

mySix.x += (mouseX - mySix.x) / random6;
mySix.y += ((mouseY + c) - mySix.y) / random6;

myNine.x += ((mouseX - c) - myNine.x) / random9;
myNine.y += (mouseY - myNine.y) / random9;

myOne.x += ((mouseX + a) - myOne.x) / random1;
myOne.y += ((mouseY - b) - myOne.y) / random1;

myTwo.x += ((mouseX + b) - myTwo.x) / random2;
myTwo.y += ((mouseY - a) - myTwo.y) / random2;

myFour.x += ((mouseX + b) - myFour.x) / random4;
myFour.y += ((mouseY + a) - myFour.y) / random4;

myFive.x += ((mouseX + a) - myFive.x) / random5;
myFive.y += ((mouseY + b) - myFive.y) / random5;

mySeven.x += ((mouseX - a) - mySeven.x) / random7;
mySeven.y += ((mouseY + b) - mySeven.y) / random7;

myEight.x += ((mouseX - b) - myEight.x) / random8;
myEight.y += ((mouseY + a) - myEight.y) / random8;

myTen.x += ((mouseX - b) - myTen.x) / random10;
myTen.y += ((mouseY - a) - myTen.y) / random10;

myEleven.x += ((mouseX - a) - myEleven.x) / random11;
myEleven.y += ((mouseY - b) - myEleven.y) / random11;
}


addEventListener(MouseEvent.MOUSE_MOVE, randomize);


//changes the speed of the numbers everytime the mouse moves
function randomize(event:MouseEvent):void
{
random12 = (8 + Math.floor(Math.random()*13));
random1 = (8 + Math.floor(Math.random()*13));
random2 = (8 + Math.floor(Math.random()*13));
random3 = (8 + Math.floor(Math.random()*13));
random4 = (8 + Math.floor(Math.random()*13));
random5 = (8 + Math.floor(Math.random()*13));
random6 = (8 + Math.floor(Math.random()*13));
random7 = (8 + Math.floor(Math.random()*13));
random8 = (8 + Math.floor(Math.random()*13));
random9 = (8 + Math.floor(Math.random()*13));
random10 = (8 + Math.floor(Math.random()*13));
random11 = (8 + Math.floor(Math.random()*13));
}

The first part of the code adds each movieclip to the stage. An event listener repositions the numbers every time you enter a new frame. The numbers are moved a fraction of the distance it will take to reach the mouse. Because the fraction of the distance gets smaller and smaller, the numbers start out moving quickly and then slow down as they get closer to the mouse. The exact fraction will be a random number between 8 and 20. An event listener resets the speeds for each number every time you move the mouse.


Test your movie. Every time you move the mouse, the numbers should move to their respective spots around it. The numbers should all be moving at different speeds, and those speeds should change everytime you move the mouse. 


6.  In the top menu, select Insert -> New Symbol, name it "secondHand". Use the line tool to draw a vertical line on the stage. In the Properties Inspector set the X to 0, the Y to -65, and the height to 65. Play with the thickness and color if you like.


7.  Insert -> New Symbol, name it "minuteHand". Use the line tool to draw a vertical line on the stage. In the Properties Inspector set the X to 0, the Y to -65, and the height to 65. Play with the thickness and color if you like.


8. Insert -> New Symbol, "hourHand". Use the line tool to draw a vertical line on the stage. In the Properties Inspector set the X to 0, the Y to -45, and the height to 45. Play with the thickness and color.


9. In the library, you need to set the linkage for your three new movieclips. Double click next to "hourHand" and type in "hourHand", double click next to "minuteHand" and type in "minuteHand", double click next to "secondHand" and type in "secondHand".


10. Open up the Actions window again. Add the following code: 

var localDate:Date = new Date();
var seconds:Number = localDate.getSeconds();
var minutes:Number = localDate.getMinutes();
var hours:Number = localDate.getHours();


var mySecondHand:secondHand = new secondHand();
addChild(mySecondHand);
var randomSeconds:Number = (8 + Math.floor(Math.random()*12));


var myMinuteHand:minuteHand = new minuteHand();
addChild(myMinuteHand);
var randomMinutes:Number = (8 + Math.floor(Math.random()*12));


var myHourHand:hourHand = new hourHand();
addChild(myHourHand);
var randomHours:Number = (8 + Math.floor(Math.random()*12));

addEventListener(Event.ENTER_FRAME,updateTime);


function updateTime(event:Event)
{
localDate = new Date();
seconds = localDate.getSeconds();
minutes = localDate.getMinutes();
hours = localDate.getHours();

mySecondHand.rotation = seconds * 6;
myMinuteHand.rotation = minutes * 6;
myHourHand.rotation = hours * 30 + minutes / 2;
trace(seconds);
}


11. Inside the "assembleClock" function, paste in this code:


 mySecondHand.x += (mouseX - mySecondHand.x) / randomSeconds;
mySecondHand.y += (mouseY - mySecondHand.y) / randomSeconds;

myMinuteHand.x += (mouseX - myMinuteHand.x) / randomMinutes;
myMinuteHand.y += (mouseY - myMinuteHand.y) / randomMinutes;

myHourHand.x += (mouseX - myHourHand.x) / randomHours;
myHourHand.y += (mouseY - myHourHand.y) / randomHours;


The "updateTime" function finds the time every time the movie enters a new frame. It then angles the hands according to the time. The second hand moves 6 degrees for every second (because 6*60 = 360), the minute hand moves 6 degrees for every minute, and the hour hand moves 30 degrees for every hour plus half a degree for each minute. I could have combined it with the "assembleClock", but I think this makes it a little more clear. 


Unless you want to resize your clock, you're done! Test your movie. It should have working hands that show the correct time and follow the mouse just like the numbers do.


If you do want to resize your clock then...


12. Each number is 65 pixels from the center of the clock, but since most of the numbers are at an angle to the center of the clock I had to find their x and y distances by using trigonometry. At the top of your code, you can see I have set three variables, a, b, and c. These are the three sides of a right triangle. Set "c" equal to the radius of your clock. In my case, c= 65. Now go to http://www.calculator.com/calcs/calc_sci.html and plug in these formulas to find a and b. 


sin(30) * c = a ("c" is what you wanted the radius of your clock to be, remember?)
cos(30) * c = b



Test your clock, make sure you're happy with the size. Now you're really done!

No comments:

Post a Comment