Typewriter Effect modification
September 19, 1999
by Pat McClellan
Dear Multimedia Handyman,
I want to create a text effect and have a blinking cursor proceed the text as the text displayed onto the screen as if typed on automatically. Can you help?
Jim Moretti
Dear Jim,
In Director 7, the library of behaviors includes a great one called "Typewriter Effect" written by Darrel Plant. This behavior can be applied to a text or field member and allows you to specify the rate at which letters will be "typed" onto the screen. The text either types on as soon as the sprite appears on stage, or you can select to have it wait for your cue. You can also choose to play a sound effect for each letter that appears.
This is a really great piece of code, so why re-invent the wheel? It does most of what we need to do, except that it doesn't display a flashing cursor preceeding the letters to be typed on. So, let's just add that to the existing behavior. Cool?
First, let's examine how the existing behavior works. In the beginSprite handler, Darrel calls a handler called mInitialize. This mInitialize handler (also sometimes called a "method" -- hence the convention of using the "m" prefix in the name) grabs the text from the cast member and stores it in a property called pText. It replaces the text in the cast member with a space. You might expect it to simply delete all of the text (so that it wouldn't appear on the screen) but it uses a space instead. This is because if you delete all the text in your cast member, then all of the formatting (font, size, etc) is deleted as well. If there's a space there, the space holds the formatting info.
mInitialize also sets a property called pIndex to 0. pIndex is the "counter" which will keep track of which letter needs to be typed onto the screen. Every time a letter appears, pIndex will be incremented by 1... up until it reaches the total number of chars in pText.
So, let's assume that you've selected to not have the text type on as soon as the sprite appears. So it will just sit there blank, waiting for the cue. (That's where we'll want to have a cursor blinking.) You cue the typing to begin by sending a message to that sprite:
sendSprite x, #mActive
The mActive handler simple "flips a switch", setting a property called pActive to TRUE. When pActive is TRUE, the mType handler executes on every new frame (prepareFrame). mType checks to see if enough time has elapsed since the last letter appeared, and if so, it increments pIndex by 1 and adds another letter from pText into the text of the cast member. It continues to do this until pIndex reaches the number of letters in pText, then it flips the switch, setting pActive to FALSE. A very nice behavior indeed.
Now let's add the blinking cursor bit. We'll want to make it an option that you can turn on or off in the getPropertiesDescriptionList dialog box (the one that appears when you drop it on a sprite.) We'll accomplish this blinking by adding either a "_" (underscore) or a SPACE to the end of the text. One other little handler I'll add is one which can pause the typing. This is very simple; it just sets pActive to FALSE.
on mPause me set pActive = FALSE end mPause
You can see how it works in this demo.
A sample movie is available for download in Mac or PC format
First, declare a new property called pCursor, and add it to the gpdl handler. It's a boolean value. When selected, it will activate the blinking cursor bit.
setaProp vPDList, #pCursor, [#comment: ¬ "Blinking cursor?", #format: #boolean, ¬ #default: FALSE]
Here are the guts of the behavior: the mType handler. Darrel has commented the handler very well, so I'm going to leave his comments and add my own to my modifications.
on mType me -- called from prepareFrame handler -- only evaluated if behavior is active if pActive then -- if index value is larger than the number of -- characters, all characters should have been shown if pIndex >= pChars then -- behavior should no longer be active pActive = FALSE else -- get current millisecond value vMillis = the milliseconds -- determine if enough time has elapsed -- since last character was shown if (vMillis - pStartTime) > pPeriod then -- increment index value pIndex = pIndex + 1 if pIndex = 1 then -- Cursor modification if pCursor then pMember.text = pText.char[1] & "_" else -- this line was in original behavior pMember.text = pText.char[1] end if else -- Cursor modification if pCursor then currentText = pMember.text delete the last char of currentText pMember.text = currentText & pText.char[pIndex] & "_" else -- otherwise each character in the text -- is concatenated with the text or field member pMember.text = pMember.text & pText.char[pIndex] end if end if -- check for sound flag, if no channel is chosen, nothing happens if pSoundChannel then -- kill sound in channel puppetsound pSoundChannel, 0 -- play sound in specified sound channel puppetSound pSoundChannel, pSound end if -- update timer value pStartTime = the milliseconds end if end if -- Cursor modification to end of handler else -- pActive is not TRUE (waiting to start, paused, or ended) if pCursor then -- blink the cursor vMillis = the milliseconds -- determine if enough time has elapsed since blink if (vMillis - pStartTime) > pPeriod * 3 then. currentText = pMember.text if the last char of currentText = SPACE then delete the last char of currentText currentText = currentText & "_" else if the last char of currentText = "_" then delete the last char of currentText currentText = currentText & SPACE else currentText = currentTExt & SPACE end if pMember.text = currentText pStartTime = the milliseconds end if end if end if end mType
That's the way it works. I know that's a lot to go through, but Darrel's original handler is so well coded that it should be a great learning experience to spend some time with it.
The additions that I made do one of two things. When pActive is TRUE and the letters are being typed on, I simply changed it so that the cursor is deleted, then the new letter is added, then the cursor is added to the end. So when the letters are being typed on, the cursor is not really blinking, it's just being appended to the string each time.
When pActive is FALSE, that means that we're waiting to start, paused, or finished. In that case, we want to have the cursor blink at the end of the string. That's a simple matter of testing to see what the last char of the string is. If it's a SPACE, then we change it to an underscore; else, it must already be an underscore and we change it to a SPACE. Pretty easy really, just a little tedious in the code.
Good luck with your program!
Copyright 1997-2025, Director Online. Article content copyright by respective authors.