AS3 Countdown Timer

Chapter three of Tucker Bowen’s Lassie game Something Amiss is on the horizon, so it’s time to get the countdown going on the Lassie website! What can is say? we love game releases!

So as I was putting the countdown banner together I recalled that this is a subject that I’ve been asked about several times in the past and have answered on several web forums: how do you make a countdown timer in Flash? My previous responses to this question have always been in AS2, so lets do something fresh and write it in AS3. Here’s a count down/up timer display composed as a class…

Save as: com/gmacwilliam/display/Countdown.as

package com.gmacwilliam.display
{
    import flash.display.Sprite;
    import flash.utils.Timer;
    import flash.events.TimerEvent;
    import flash.events.Event;
    import flash.text.*;

    public class Countdown extends Sprite
    {
        private var _countUp:TextField;
        private var _countDown:TextField;
        private var _timer:Timer;
        private var _startTime:Number;
        private var _expireTime:Number;
        private var _range:Number;

        public function Countdown(refreshSecs:Number, year:int, month:int=1, day:int=1, hour:int=0, minute:int=0, second:int=0, ms:int=0):void
        {
            super();

            // create TextField displays
            _countUp = new TextField();
            _countDown = new TextField();
            _countUp.defaultTextFormat = _countDown.defaultTextFormat = new TextFormat("_sans", 24);
            _countUp.antiAliasType = _countDown.antiAliasType = AntiAliasType.ADVANCED;
            _countUp.autoSize = _countDown.autoSize = TextFieldAutoSize.LEFT;
            _countUp.selectable = _countDown.selectable = true;
            _countUp.y = 0;
            _countDown.y = 50;
            addChild(_countUp);
            addChild(_countDown);

            // configure start, end, and duration values.
            _startTime = new Date().getTime();
            _expireTime = new Date(year, month-1, day, hour, minute, second, ms).getTime();
            _range = _expireTime - _startTime;

            // configure timer interval.
            _timer = new Timer(refreshSecs * 1000);
            _timer.addEventListener(TimerEvent.TIMER, this._onRefresh);
            _timer.start();
            refresh();
        }

        /**
        * Refreshes countdown display.
        */
        public function refresh(evt:Event=null):void
        {
            var elapsed:Number = new Date().getTime()-_startTime;
            _countUp.htmlText = _small("count up: ") + _getTimeDisplay(elapsed).toUpperCase();
            _countDown.htmlText = _small("count down: ") + _getTimeDisplay(_range-elapsed).toUpperCase();
        }

        /**
        * Disposes of countdown display so that it is eligible for garbage collection.
        */
        public function dispose():void
        {
            _timer.stop();
            _timer.removeEventListener(TimerEvent.TIMER, this._onRefresh);
            _timer = null;
        }

        /**
        * Generates countdown string from remaining time value.
        */
        private function _getTimeDisplay(remainder:Number):String
        {
            // days
            var numDays:Number = Math.floor(remainder/86400000);
            var days:String = numDays.toString();
            remainder = remainder - (numDays*86400000);

            // hours
            var numHours:Number = Math.floor(remainder/3600000);
            var hours:String = (numHours < 10 ? "0" : "") + numHours.toString();
            remainder = remainder - (numHours*3600000);

            // minutes
            var numMinutes:Number = Math.floor(remainder/60000);
            var minutes:String = (numMinutes < 10 ? "0" : "") + numMinutes.toString();
            remainder = remainder - (numMinutes*60000);

            // seconds
            var numSeconds:Number = Math.floor(remainder/1000);
            var seconds:String = (numSeconds < 10 ? "0" : "") + numSeconds.toString();
            remainder = remainder - (numSeconds*1000);

            // milliseconds
            //var numMilliseconds:Number = Math.floor(remainder/10);
            //var milliseconds:String = (numMilliseconds < 10 ? "0" : "") + numMilliseconds.toString();

            return "<FONT SIZE='24'>"+ days + _small("days") + hours + _small("hrs") + minutes + _small("mins") + seconds + _small("secs") + "</FONT>";
        }

        /**
        * Utility for wrapping value labels in a tag with smaller text.
        */
        private function _small(label:String):String
        {
            return "<FONT SIZE='12'> "+label+"</FONT> ";
        }

        /**
        * Timer event handler to call refresh.
        */
        private function _onRefresh(evt:Event):void
        {
            refresh();
        }
    }
}

Implementation of that example class is pretty simple. Just import the class into a FLA document, create an instance of the Countdown class and add it to your display. When creating a Countdown object, constructor parameters are as follows:

new Countdown(refreshIntervalSeconds:Number, year:int, [month:int=1, day:int=1, hour:int=0, minute:int=0, second:int=0, millisecond:int=0]);

The class will take care of creating all TextField displays, so you don’t need any supporting library items. The full instantiation of this countdown display looks like this:

import com.gmacwilliam.display.Countdown;
// Countdown displaying the time until Halloween 2008. Refreshes once a second.
addChild(new Countdown(1, 2008, 10, 31));

You’ll notice that this example includes timers that are counting both up and down to the target time. You probably won’t ever need to display both values at the same time, but this should illustrate how to arrive at either value. Feel free to adapt and adjust the class to your needs!

Advertisements

6 comments so far

  1. Chris on

    Very nice. Its really interesting to see the countdown on the site, and then see whats going on in the background here.

  2. bigmac on

    LOL… to be entirely honest, this isn’t the exact code at work there. I wrote this all as timeline actions in a quick and dirty implementation, then copied the code into this class architecture specifically for this example. Having a class that you can quickly and easily instantiate is the fastest way to showcase a demo I find. But otherwise, yes… all the math and date methodology is the same as the live counter.

  3. janusz on

    hi, was just looking at the script and i have used it to countdown to a date.

    If however, i put in 10th May 2009, im only getting 17 days from today (Jan 12th) to the 10th May.

    • bigmac on

      WOW. Good catch… unbelievably weird. I’ve never run into this nuance of AS3 before: I had typed several of the whole numbers as “int”, which apparently has a significantly lower byte limit than the Number class. So, short-term dates which yeild small numbers worked fine, but longer-range dates would have their calculations mashed up by “int” data limits. I’ve updated this class to use Numbers for all data types which fixed it up. So, try it now…

      Thanks for posting that error, that was really strange and informative. I’ll be much more cautious about using “int” in the future.

  4. janusz on

    i have not checked it yet, but im sure it will be okay.

    The client opted for just hours and mins… so this class worked fine!

    Thanks for the feedback, thought i may have been doing something wrong.

  5. Colon on

    Hello this is great code but I was wondering how to make a pause function.

    Can you help me how would or should make a pause function that work with your countdown class.

    Thanks


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: