TimeOut

From Director Online Wiki
Jump to: navigation, search

TimeOut objects were introduced in Director 8.0. They can be used to call a handler in a Movie Script or an object instance on a (fairly) regular basis.

Prior to Director 8.0, the expression 'timeOut' was used only to refer to movie level properties and handlers that are called when no user activity is detected after a given period of time. If this is the subject you are looking for, then choose one of the following links: on timeOut() (movie event)? timeOutKeyDown, timeOutLapsed, timeOutLength, timeOutMouse, timeOutPlay, timeOutScript.

TimeOut methods

  • new()

A new timeOut object is created in one of the following ways:

Director MX 2004 (10.x)

vTimeOut = timeOut().new("Time Out Name", 1000, #timeOutHandler {, object})

In order to create a timeout, which works in all director versions do:

vTimeOut = timeOut("Time Out Name")
if ilk(vTimeOut) = #timeout then vTimeOut = timeOut("Time Out Name").new(1000, #timeOutHandler {, object})
else  vTimeOut = timeOut().new("Time Out Name", 1000, #timeOutHandler {, object})

Director 8.0 to MX (9.0)

vTimeOut = timeOut("Time Out Name").new(1000, #timeOutHandler {, object})

When a new timeOut object is created, it is automatically added to the timeOutList. From that moment on, the timeOutHandler in the target object (or in a Movie Script if no object is defined) will be called after intervals of 'at least the timeOut period (1000 milliseconds in the above example).

  • forget()

To destroy a timeOut object, call its forget method:

vTimeOut = timeOut("Time Out Name")
vTimeOut.forget()      -- removed from the timeOutList
vTimeOut = VOID        -- cleared from memory

A timeOut object can persist in the computer's RAM space if it held in a variable, even if it no longer appears on the timeOutList.

While trying to forget a non exist timeOut in Director 8.0 to MX (9.0) will not cause anything, it will yield a script error in Director MX (10.0) (added by Yochai)

To avoid script errors in D10 always check for the object's ilk. Since timeout("Non existing") yields void, instead of an automatically created timeout object (D 8 to D9), you can't call the method forget() on a void value. Instead you can always do the following:

if ilk(timeout("Non existing")) = #timeout then timeout("Non existing").forget()


TimeOut properties

  • name

String name for the timeOut object. Only one timeOut object with a given name can exist for a given window.

  • period

Integer number of milliseconds used as the minimum period between each call to the timeOutHandler. A value of 0 means that the timeOutHandler will never be called.

  • timeOutHandler

Symbol handler name to be called at intervals defined by the period. The default value is #timeOut. If there is no handler definition in the target object or the Movie Scripts, then the call will fail gracefully.

While you can set the timeOutHandler to a string, this is not recommended, the value will be converted to a symbol and may be altered in the process.

vTimeOut = timeOut("Test")
put vTimeOut.timeOutHandler
-- #timeout
vTimeOut.timeOutHandler = "string with more than one word"
put vTimeOut.timeOutHandler
-- #string

Attempting to set the timeOutHandler to a Lingo type other than a symbol or a string will result in a Script Error.

In Director MX (9.0) and earlier, it is possible to create a timeOut object without initialising it using the new() method. The default timeOutHandler for such a timeOut is #timeOut. If you are using an on timeOut() handler to check for user inactivity, you may encounter compatibility issues. It is therefore best explicitly to use a timeOutHandler other than #timeOut.

  • target

Optional property. If this is a script or instance, Director will send the timeOutHandler event to the target object first. If it is not a script or instance, or if the target object does not contain the required handler, the event will be forwarded to the first Movie Script that contains a handler with the same name as the timeOutHandler.

  • persistent

FALSE by default. If explicitly set to TRUE, the timeOut object will persist even if the playback head jumps to a different movie. If FALSE, then the timeOut object will be removed from the movie's timeOutList after it has sent its #stopMovie event (see Movie Events below).

  • time

Time in milliseconds of the earliest possible next activation of the timeOutHandler. The timeOutHandler will be called as soon after the milliseconds reaches this value as Director can manage.

The .time property is set automatically when you alter the .period property.

If you set this property to:

    • An integer value greater than the milliseconds, Director will pause the action of the timeOut object until that value of the milliseconds is reached
    • A non-negative integer value less than the milliseconds, Director will activate the object's timeOutHandler at the first available opportunity
    • A negative integer, Director will pause the activity of the timeOut object indefinitely. Using values of (say) 1 (on) and -1 (off) allows you to toggle the timeOut object on and off, without varying its .period.

Movie Events

Any object that is the target of a timeOutObject will receive the following movie events:


The timeOutObject itself is sent as the second parameter of the call (see Passing Parameters to a Movie Script, below, for information on the first parameter):

on startMovie(aParameter, aTimeOutObject)
  if ilk(aTimeOutObject, #timeOut) then
    -- This event was issued by a timeOut object, not the movie
  end if
end startMovie

If no target is defined, these events will not be sent to appropriate Movie Script handlers. However, the following scenario will lead to 'multiple events being received by the same Movie Script handler by default.

You create a timeOut object, with an object as its target. Neither the object nor any of its ancestors contains any movie event handler (this is the norm). Director will therefore forward the movie events generated by the timeOut object to your Movie Script handlers instead.

To ensure that your movie script handlers are executed only once, it is advisable to include a test for the source of the call. For example:

on stopMovie(aParameter, aTimeOutObject)
  if ilk(aTimeOutObject, #timeOut) then
    -- The call came from a timeOut object, not the movie itself
    exit
  end if
  -- do stopMovie stuff here
end stopMovie

Passing Parameters to a Movie Script

The value used as the .target of a timeOut object is always sent as the first parameter of the call. If the .target is a script or instance and it contains the appropriate handler, the event will be sent to that object. If not, the event will be sent to the appropriate handler in a Movie Script. You can thus use the .target property to pass a parameter to a Movie Script:

on startMovie()
 vTimeOut = timeOut().new("Pass Parameter", 1000, #movieHandler, [#parameter])
end startMovie


on movieHandler(aParameter, aTimeOut)
  put aParameter
end movieHandler


In the Message window

-- [#parameter]

Caveat: In this example the parameter is an object (lists are objects). This timeOut will not find any Movie Event handlers in the object in question, and so will forward duplicate Movie Events to the appropriate Movie Script handlers (see above). This will not occur if the .target is not an object (e.g. "string" or #symbol).

Timing

TimeOut handlers are called between #enterFrame and #exitFrame, interspersed with the #idle events.

Contrary to popular belief, timeOut handlers are not called at precise intervals. The timeOut.period defines the shortest interval between two calls to a timeOut handler. If the movie or the system is busy dealing with other issues, the timeOut period will be stretched. The timeOutHandler will not be called until after the system (or Director) releases the resources. The calls to #enterFrame - or any frame event for that reason - is irrelevant; if you stop Director's head issuing a pause command, the frame events will not be triggered, but the timeOut object will continue the calls to the handler.

Here's a handler that lets you see how much delay occurs.

on timeOutHandler(aParameter, aTimeOut)
  if ilk(aTimeOut, #timeOut) then
    vMilliseconds = the milliseconds
    vTime         = aTimeOut.time
    vDelay        = vMilliseconds - vTime
    put RETURN&\
"Called:   "&vMilliseconds&RETURN&\
"Expected: "&vTime&RETURN&\
"Delay:    "&vDelay
  end if
end timeOutHandler

In the Message window:

-- "
Called:   5510505
Expected: 5510501
Delay:    4"
-- "
Called:   5515518
Expected: 5515505
Delay:    13"
-- "
Called:   5520525
Expected: 5520518
Delay:    7"

In this example, note how the Expected time for each call is exactly 5000 milliseconds after the previous call. This corresponds to a .period of 5000.

Instead of giving the metronome accuracy that many developers expect, timeOut events will tend to drift further and further from a regular beat.

Scope

Each window maintains its own list of timeOut objects. Calls to timeOutHandlers are made within the scope of the window.