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.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.