Articles Archive
Articles Search
Director Wiki
 

Making timers that display in Time format

July 6, 2000
by Gary Rosenzweig

It seems that recently I have been dealing with time a lot in the Lingo Lounge. Here is yet another aspect of time we can look into: timers. Not only can we make a Lingo behavior count up from a point in time, or count down to a point in time, but we can also display this timer in a familiar format.

The two primary ways that you can tell time in Director are the ticks and the milliseconds. The latter is more precise, so we will deal with the milliseconds in this article. The function the milliseconds counts thousandths of a second since Director, the Projector, or the Shockwave movie started. You can record the value of the milliseconds when the timer starts, and then calculate the current time by subtracting the original value of the milliseconds from the current value.

If you want to count down to a certain time, then you can record the original value of the milliseconds, plus the amount of time that the timer will count. So, if you want the timer to count down 60 seconds, you can record the milliseconds, plus 60 times 1,000. Then, you subtract the current value of the milliseconds from this original value.

Using behavior properties, you can specify a starting time, whether the timer counts up or down, and whether the timer will start automatically or wait for a sendSprite command to trigger it. Here is the part of the behavior's code that does the counting:

property pTimerStart
property pTimerDirection
property pStartImmediately
property pTimerRunning
property pStartTime
property pCurrentString

on getPropertyDescriptionList me

  list = [:]

  addProp list, #pTimerStart, [#comment: "Starting Time (seconds)", #format: #integer, #default: 0]
  addProp list, #pTimerDirection, [#comment: "Timer Direction", #format: #string, #range: ["Count Up", "Count Down"], #default: "Count Up"]
  addProp list, #pStartImmediately, [#comment: "Start Immediately", #format: #boolean, #default: TRUE]

  return list

end

-- reset time, start timer if supposed to
on beginSprite me
  reset(me)
  if pStartImmediately then start(me)
end

-- set time to 0 and show it
on reset me
  pTimerRunning = FALSE
  showTime(me,0.0)
end

-- mark 0 time relative to direction of timer
-- start running
on start me

  if pTimerDirection = "Count Up" then
    -- start here and count up from 0
    pStartTime = the milliseconds
  else
    -- count down from pTimerStart
    pStartTime = the milliseconds + pTimerStart*1000
  end if

  pTimerRunning = TRUE
  pCurrentString = ""

end


on exitFrame me

  if pTimerRunning then
    
    -- get the current milliseconds
    if pTimerDirection = "Count Up" then
      currTime = the milliseconds - pStartTime
    else
      currTime = pStartTime - the milliseconds
      if currTime < 0 then currTime = 0
    end if
    
    showTime(me,currTime)
  end if

end

The only part of the behavior that is missing is the on showTime handler. This is what will take a value in milliseconds and display it in hours, minutes, seconds and even fractions of a second. The format will be something like this: "HH:MM:SS.SSS".

You should also consider that you may not want to display hours all of the time. If your timer is only counting down from 60 seconds, for instance, then there is no point in counting hours. Using a few more behavior properties, you can make hours optional. You can also make minutes optional, and set the number of decimal places shown. Here are the new properties:

property pShowHours
property pShowMinutes
property pDecimalPlaces

Here are how they appear in the on getPropertyDescriptionList handler:

addProp list, #pShowHours, [#comment: "Show Hours", #format: #boolean, #default: FALSE]
addProp list, #pShowMinutes, [#comment: "Show Minutes", #format: #boolean, #default: TRUE]
addProp list, #pDecimalPlaces, [#comment: "Number of Decimal Places", #format: #integer, #range: [0,1,2,3], #default: 1]

The on showTime handler takes a number, representing milliseconds, and determines the seconds, minutes and hours from it. It also determines how many milliseconds are left over.

Then, it puts together a string based on the choices made in the behavior properties dialog. It can put together something as simple as seconds: "SS", or something complex as hours, minutes, seconds, and milliseconds: "HH:MM:SS.SSS".

-- create time string from integer

on showTime me, millisec

  -- calculate hours, minutes, seconds and milliseconds
  sec = integer(millisec/1000)
  min = integer(sec/60)
  sec = sec - min*60
  hour = integer(min/60)
  min = min - hour*60
  millisec = millisec - sec*1000 - min*60*1000 - hour*60*60*1000

  -- show hours if requested
  if pShowHours then
    hourString = string(hour+100).char[2..3]&":"
  else
    hourString = ""
  end if

  -- show minutes if requested
  if pShowMinutes then
    minString = string(min+100).char[2..3]&":"
  else
    minString = ""
  end if

  -- always show seconds
  secString = string(sec+100).char[2..3]

  -- milliseconds
  if pDecimalPlaces = 0 then
    milliString = ""
  else
    milliString = string(millisec+1000).char[2..4]
    -- cut down to number requested
    milliString = "."&milliString.char[1..pDecimalPlaces]
  end if

  -- create time string
  text = hourString&minString&secString&milliString

  -- update text member only if needed
  if text <> pCurrentString then
    sprite(me.spriteNum).member.text = text
    pCurrentString = text
  end if

end

As you can see, this behavior expects to be placed on a text or field sprite. The time string is placed directly into the sprite's member's text property. To save time, the new time string is compared to the last one displayed. If they are the same, then no attempt is made to reset the text member. So, for instance, if "01:59" is displayed once, and the next time through the time is still "01:59", then the text member will not be updated.

Here is this behavior in action. The first button will begin a count up starting at 0 and displaying hours, minutes, seconds, and two decimal places of seconds. The second button will begin a count down from two minutes using minutes, seconds and one decimal place.

A Director 8 sample movie is available for download in Mac or PC format.

While this behavior can operate completely by itself, you will most likely want to connect it to another part of your program. If another handler in your movie wants to get the current time, you can add a handler like this to return it:

on getTime me
  return the milliseconds - pStartTime
end

Then, you can simply use sendSprite(7,#getTime) , where 7 is the sprite being used for the timer, to get the current time. If you are counting down instead of up, you can alter the on exitFrame handler to signal another behavior or movie handler once the currTime is less than or equal to zero.

Other possibilities include having timers that don't show seconds, but only minutes and hours. This behavior only works for times less than 100 hours, but you can easily alter it to show 100 or more hours, or possibly show days as well. You can also alter it, with a little more work, to show negative time.

Gary Rosenzweig's latest book is "Advanced Lingo for Games." In it, you can find the source code for more than 20 complete games. More information about the book can be found at http://clevermedia.com/resources/bookstore/book4.html. It can be purchased there, or in your local bookstore.

Gary Rosenzweig is the Chief Engineer, founder, and owner of CleverMedia, a game and multimedia development company in Denver, Colorado. He is the author of ten books on Macromedia Director and Flash, including his latest, Special Edition Using Director MX.

Copyright 1997-2017, Director Online. Article content copyright by respective authors.