-1

How does one start two animated analog clocks displaying the same initial time, then make one twice as fast as the other so that one second becomes a half-second, et cetera so that it races past the "real-time" clock? The trick is that they need to both start displaying the current time.

I know this may be simple, but every time I add a multiplier to the variables of clock two it starts at the incorrect time and skips ticks.

Here's the ActionScript I used as a starting point (both clocks are the same):

var now:Date;
var ct:Timer = new Timer(1);
ct.addEventListener(TimerEvent.TIMER, onTick);
ct.start();

function onTick(event:TimerEvent):void {
now = new Date();
var s:uint = now.getSeconds();
var m:uint = now.getMinutes();
var h:uint = now.getHours();
/*CLOCK ONE*/
one_second_hand_mc.rotation = 180 + (s * 6);
one_minute_hand_mc.rotation = 180 + (m * 6);
one_hour_hand_mc.rotation = 180 + (h * 30) + (m / 2);
/*CLOCK TWO*/
two_second_hand_mc.rotation = 180 + (s * 6);
two_minute_hand_mc.rotation = 180 + (m * 6);
two_hour_hand_mc.rotation = 180 + (h * 30) + (m / 2);
}
Dylan
  • 495
  • 1
  • 6
  • 19

2 Answers2

1
  1. It's a bad practiсe to set a timer delay less than 20 milliseconds: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html#delay

  2. Try something like this (I show only seconds for simplicity):

var now:Date;
var ct:Timer = new Timer(500);
ct.addEventListener(TimerEvent.TIMER, onTick);

now = new Date();
var s:uint = 180 + 6 * now.getSeconds();
/CLOCK ONE/
one_second_hand_mc.rotation = s;
/CLOCK TWO/
two_second_hand_mc.rotation = s;

ct.start();

var secondStep:Number = 6; // 360 / 60 (divisions on a clock face)
var minutStep:Number = 0.1; // 6 / 60 (seconds in minute)
var hourStep:Number = 1/ 600; // 6 / 3600 (seconds in hour)

function onTick(event:TimerEvent):void {

/CLOCK ONE/
if (!(ct.currentCount % 2)){
one_second_hand_mc.rotation += secondStep;
one_minute_hand_mc.rotation += minuteStep;
one_hour_hand_mc.rotation += hourStep;
}

/CLOCK TWO/
two_second_hand_mc.rotation += secondStep;
two_minute_hand_mc.rotation += minuteStep;
two_hour_hand_mc.rotation += hourStep;
}

Emin A. Alekperov
  • 1,067
  • 1
  • 16
  • 26
  • I've managed to get this to work with seconds, but am still having trouble with minutes and hours. What would the variable equation be for minutes and hours? I tried the obvious, multiply the minutes by 6 and the hours by 30 plus minutes divided by 2, but this seems to be wrong. – Dylan Oct 04 '12 at 22:43
  • I've updated my answare by adding code for minutes and hours. – Emin A. Alekperov Oct 05 '12 at 09:08
  • Also you should note that in real life minute and hour arrows can get intermediate position between divisions. – Emin A. Alekperov Oct 05 '12 at 09:22
  • Ah yes, this is usually accomplished by "(h * 30) + (m / 2)", correct. This way the clock isn't misleading. would you please explain why minutStep uses .1 and the hourStep uses 1/600 and why the Number type instead of uint? – Dylan Oct 05 '12 at 17:18
  • 1. One minute devision corresponds to 6 degrees. There are 60 seconds in one minute. So, after 60 seconds a minute arrow should move 6 degrees. Than after 1 seconds the minute arrow should move 6 / 60 = 0.1 degree. The same situation with hours. One hour corresponds to 6 degrees. There are 3600 seconds in one hour. So, after 1 second an hour arrow should move 6 / 3600 = 1 / 600 degree.
    2. uint is an integer number. But a step is a float (0.1 and 1 / 600). I can use uint for 'secondStep'. But for uniformity I use 'Number'. Maybe it is better to use uint for 'secondStep'.
    – Emin A. Alekperov Oct 05 '12 at 22:51
1

Here's an alternative approach. The idea is to to store the current start time once. Then every time you want to update the clock (onTick), you check how much time has passed since the start time and create a new date object that represents the start time + the time passed scaled with a factor. If the factor is larger than 1 then the clock moves faster than realtime, if it's lower it moves slower.

If you run onTick often you get a smooth animation, but you can run it once a second or whichever interval you want.

// store current start time in milliseconds
var startTime : Number = new Date().getTime();

// the delay in the Timer doesn't affect the time
// displayed by the clocks, but only determines
// how often the clocks should be updated (redrawn)
var ct:Timer = new Timer(50);
ct.addEventListener(TimerEvent.TIMER, onTick);
ct.start();


function onTick(event:TimerEvent):void {
    // first clock should run at normal speed so we send in 1 as scale factor
    var timeDataOne : Object = calculateTime(1);
    // second clock at double speed (send in 0.5 to run at half speed)
    var timeDataTwo : Object = calculateTime(2);

    one_second_hand_mc.rotation = 180 + (timeDataOne.s * 6);
    one_minute_hand_mc.rotation = 180 + (timeDataOne.m * 6);
    one_hour_hand_mc.rotation = 180 + (timeDataOne.h/12) * 360;

    two_second_hand_mc.rotation = 180 + (timeDataTwo.s * 6);
    two_minute_hand_mc.rotation = 180 + (timeDataTwo.m * 6);
    two_hour_hand_mc.rotation = 180 + (timeDataTwo.h/12) * 360;
}


function calculateTime(clockSpeed : Number = 1):Object {
    // current time in milliseconds
    var nowTime : Number = new Date().getTime();

    // how many milliseconds have passed from the start time
    var timePassed : Number = nowTime - startTime;

    // create a new date object which should hold the time to display
    var displayTime : Date = new Date();

    // here we set the date object, which is based on the start time
    // plus the time passed multiplied with a scale factor clockSpeed.
    // When clockSpeed is one, displayTime will match the current time.
    displayTime.setTime(startTime + timePassed * clockSpeed);

    // calculate seconds, minutes and hours (and since the clock is analog
    // we use Number so we don't get discreet steps for the clock hands)
    var s : Number = displayTime.getSeconds() + (displayTime.getMilliseconds()/1000);
    var m : Number = displayTime.getMinutes() + s / 60;
    var h : Number = (displayTime.getHours() % 12) + m / 60;

    return { s: s, m: m, h: h };
}
Strille
  • 5,741
  • 2
  • 26
  • 40