Articles Archive
Articles Search
Director Wiki
 

TimeOut, timer scripts and timer objects

June 20, 1999
by Pat McClellan

Dear Multimedia Handyman,

I have a project which will be shown in a museum for four weeks. The project will run from cd-rom, on a mac. there are twelve movies in the project. It's important that the viewer always start from the 1st movie. Is there a way I can have the 1st movie reload, sort of like a refresh function, if any of the other movies are idle for an extended time?

2nd related question - is there a way to trigger a timed help button? For example, movie play is paused waiting for an action. Instead of making a big obvious button, I want the viewer to try to look for device. But since this is in a museum context, I can't rely upon all viewers being familiar with interactive concepts. If action is idle or it seems as though someone is stuck, I want to have a help button pop up. Thank you

Tana

Dear Tana,

First, an opinion. In a museum kiosk situation, your controls need to be very obvious -- most people are dumb, particularly when trying to figure out a new interface. I wouldn't hide any of the device controls. Keep in mind that the content is more important than having a clever interface, so let the users focus on what they're there to learn about. Again, that's an opinion so do with it as you please.

Now, the facts. Both of your questions relate to having something happen after a period of time. For your first question, I'd use "the timeOutScript". Check your Lingo dictionary for the full explanation. As an example, let's assume you want it to reset after 15 seconds of no mouse or keyboard input. Also, for this example, I'm supposing that your first movie is actually called "firstmovie". You'll need to create a movie script like this...

on startMovie
  set the timeOutLength to 15 * 60
  set the timeOutScript to "resetMovie"
end
on resetMovie
  go to movie "firstmovie"
end

That's all you need (but you need to have the resetMovie handler in all of your movies). Timeout is measured in "ticks" or 1/60th of a second, so by setting the timeOutLength to 15 * 60, it's an easy way to read it so you know immediately how many seconds there are (instead of 900 ticks).

TimeOut watches both the keyboard and the mouse, so it really wouldn't work as a solution to your second question because the user might be using the mouse but still need help. For that, I'd create a little "timer" handler which can be turned on when you enter the section you want to time, and turned off as soon as the user clicks whatever they're supposed to click. Take a look in the Lingo dictionary at the "startTimer" and "the timer" keywords. That's what we'll be using.

"The timer" is a ever-present global value in Director which you don't need to declare as a global. Just for kicks, enter "put the timer" in the message window. It will return a value (measured in ticks). Now, enter "startTimer", followed quickly by entering "put the timer" again. When you enter startTimer, it resets the timer to zero and starts counting again.

So, when you want to start the timer in a section, you'll need to put "startTimer" in a frame script (but make sure it's not a frame that gets looped in.) Now, we need a way to check the timer. I'll assume that we want to give the user 8 seconds before sending them to a frame called "help". Just put the following frame script in every frame in that section.

on exitFrame
  if the timer > 8 * 60 then
    go to frame "help"
  end if
     
end

Once the user clicks on the target, you can either jump to a frame where the script isn't present (effectively turning the alarm clock off), or startTimer again if there's another timed period.

If you're ready to advance your Lingo a bit, I'll show you how to write a "parent script" which is a timer "object". Conceptually, what we're going to do is create an independent little timer object which will count (on its own) for the specified number of ticks, then -- assuming that it hasn't been cancelled by the user's click -- it will go to the help frame and dispose of itself. Cool, huh?

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

Take a look at this little demo movie. It contains a "parent script". Before I understood object oriented programming concepts, parent scripts sounded very abstract and complicated. But then, when Director 6 came out with behaviors, it changed my whole perception. Think of a parent script just like a behavior -- only you don't have to attach it to a sprite. You can just tell it to come into existence and then it does whatever it does until it is told to go away. When you write a parent script, you have to click on the INFO (blue i) button in the script window and set its type to "parent".

Here's the parent script that I used in the demo. I named the script cast member "timerToGo". (You'll need to know the name in order to call it.)

-- parent script "timerToGo"
-- copyright © 1999, ZZP Online, LLC
-- free use for Director Online readers
property pStartTicks, pWaitTicks
proeprty pWhichFrame, pWhichMovie
global gTimer
on new me, howLong, frameName, movieName
  set pStartTicks = the ticks
  set pWaitTicks = howLong
  set pWhichFrame = frameName
  
  if not voidP(movieName) then
    set pWhichMovie = movieName
  end if
  add the actorList, me
  return me
  
end
on stepFrame me
  if the ticks > pStartTicks + pWaitTicks then
  
    if not voidP(pWhichMovie) then
      go to frame pWhichFrame of movie pWhichMovie
    else
      go to frame pWhichFrame
    end if
    
    deleteOne the actorList, me
    set gTimer = 0
    
  end if
  
end
on killTimer me
  deleteOne the actorList, me
  set gTimer = 0
  
end

To call the object into existence, all you do is use the new() command. You can read the actual script that calls it from the big, colored buttons in the demo. You just say...

new(script <scriptname>, <parameter>, <parameter>)

Obviously, you'll need to insert the name of your specific parent script, and then supply any needed parameters. In this demo, I figured we might want to use this object but with different time delays and "go to" frames (or go to movie), so I made those variable parameters which you can supply.

When you call the script with a new() command, the on new handler gets executed. In that handler, I set the object's properties to the parameter values supplied in the call. For example, when you press the top button, you'll see that I specify 120 ticks, so this instance of the object will set its property pWaitTicks to 120. But if you press the second button, the object instance sets pWaitTicks to 240.

In this demo, the go to frame is in the same movie, so there's no need to specify a movie. In fact, I don't include the movie name in the new() command. So when the object's new handler gets down to setting pWhichMovie, if there is no value specified, it just ignores it.

The last two lines of the script's new handler are important and unique to parent scripts. First, I add the name of the object to the actorList. If you've never dealt with objects, then you probably don't know about the actorList. Like "the timer", it's another ever-present bit of data in every Director movie. Here's what it does. Director sends a message on every exitFrame to every object on the actorList. It's like Director saying to each object, "Hey, do whatever you're supposed to do on each new frame." Okay, I'm paraphrasing a bit. What it actually says is "stepFrame".

So on every new frame, our object script gets sent the message to "stepFrame". When it gets that message, it executes the on stepFrame handler. We'll talk about that in a minute. First I want to talk about that last line: "return me".

When you click one of the big buttons in the demo, you'll see the object get added to the actorList. The name that gets added to the actorList is something like , though the name is different for each new object. That means that we never know exactly what name Director will assign to the object instance, so we need to figure out an easy way to refer to the object. As you'll see on those big buttons, I set a global variable (gTimer) equal to the new object. When the new handler in the object script gets down to "return me", it spits the name (for example) back out and assigns that to gTimer. That means that we don't have to know the "real" name, we can just call it by its "nickname", gTimer. We'll need that when it comes time to "kill" the timer.

Now look through the stepFrame handler. It checks to see if the specified amount of ticks has elapsed since the object was first born. If not, then nothing happens this frame. If so, then it goes to frame "help", and then it does something very important: it disposes of itself. When an object's work is done, it's important to clear it out of memory so that things don't get cluttered. To dispose of an object, you simply remove any reference to the object's name. We know that the object's name exists in 2 places: the actorList, and as the value for gTimer. So, to dispose of the object, we need to delete it from the actorList, and then set gTimer to VOID.

Since you want the user to be able to avoid the timer running out, we'll need to have a way to kill the timer object. For that, I created the killTimer handler. And this is where I need to use the gTimer name. On the button in the demo called KillTimer, this is the script:

on mouseUp
  global gTimer
  
  if voidP (gTimer) then
    alert "No timer is active"
  else
    killTimer gTimer
  end if
  
end

It checks to see if gTimer has a value (if it is not VOID) and if there is an object assigned to gTimer, it sends it the killTimer command. That's when that last handler in the object script gets executed. Just like in the stepFrame handler, it disposes of itself by deleting itself from the actorList and setting gTimer to VOID.

If you're still reading, then I give you credit for slogging through this explanation when it was simpler just to use the regular frame script approach. I'm not saying that using an object to do this simple timer operation is "better", but for many more complicated tasks, objects do things that frame scripts would really struggle with. This timer function just made a good example with which I could introduce some of you to objects.

If you open up your mind to the possibilities, you'll find that object oriented programming is quite elegant because you don't have to keep "watching things". With objects, they watch themselves and keep track of their own property values. So if you set things up correctly, the program can pretty much take care of itself. In some situations, you have objects which create other objects when needed!

If you're interested in learning more about OOP (object oriented programming), I'd recommend searching through our archives on the obvious keywords. We've got several great articles by Steve Kury, Paul Hemmer, Zac, and others. Good luck with your project, and I hope I've piqued your interest in OOP.

Patrick McClellan is Director Online's co-founder. Pat is Vice President, Managing Director for Jack Morton Worldwide, a global experiential marketing company. He is responsible for the San Francisco office, which helps major technology clients to develop marketing communications programs to reach enterprise and consumer audiences.

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