DreamLight Interactive

DreamLight Director Talisman


Search/Index Help
Click to view DreamLight's 3D Animation Demo Reel
20+ Years of Award-winning Multimedia, 1987-2007

The actorList & other Lingo Problems, Issues, Bugs
& DreamLight Director Talisman Tips & Tricks

DreamLight DreamObjects

Now you can use DreamLight DreamObjects LingOOP Framework for rapid Director development. Download the free example DLI_ActorMan, the actorList manager.

Previous Contents Next

I have compiled and edited some of my past Direct-L posts about many miscellaneous Lingo issues here for convenient reference. Armed with these tips & tricks, you should be able to write more effective, error free Lingo code.

The actorList is so useful we’ve used it for all sorts of projects including the award-winning KeyQuest edutainment CD-ROM and also Quipples: The Internet Game Show of Satirical Riddles. I had even implemented my own TheActiveObjects stack way back in Director 3’s factories for the original version of DreamLight Verttice. This was in 1992, well before there was an official actorList, but the concept was the same. My original Lingo source code was then included in Macromedia's first Authorized Developer CD-ROM, as an example of object oriented programming with Lingo.

There are many rumors about the actorList being as mysterious and dangerous as the Bermuda Triangle. Well, I’m here to tell you that it is not at all that difficult and can be quite useful. The greatest pitfalls arose in Director 4 by deleting actorList objects in stepFrames, pulling the rug out from under your poor object’s feet. This used to cause various crashes. Director 5 was much more stable and Director 6 through 8.5.1 and later seem rock solid.


Michael Scaramozzino

Michael Scaramozzino
President and Creative Director

DreamLight Director Talisman
Director Tips & Tricks

Authorized Macromedia Developer



ilk() Lingo Dictionary Corrections


Date: Feb. 12, 2002

D8.5.1 Lingo Dictionary, Page 239, ilk()

The table is incorrect, so I wrote a little handler called "ilkTest" that you can use to generate the correct table, right from the ilk()'s mouth.

Running ilkTest in the message window will generate the following:

-- "X=              ilk(X)     ilk(X,Type) = 1    Example"
-- ""
-- "integer         #integer   #number #integer   ilk( 128 )"
-- "float           #float     #number #float     ilk( 128.128 )"
-- "string          #string    #string            ilk( "A String" )"
-- "linear list     #list      #list #linearList  ilk( [1,2,3] )"
-- "property list   #propList  #list #propList    ilk( [#A:1,#B:2] )"
-- "rect            #rect      #list #rect        ilk( rect(0,0,640,480) )"
-- "point           #point     #list #point       ilk( point(320,240) )"
-- "color           #color     #color             ilk( rgb("#FFFFFF" ) )"
-- "date            #date      #date              ilk( the systemDate )"
-- "symbol          #symbol    #symbol            ilk( #symbol )"
-- "picture         #picture   #picture           ilk( (the stage).picture )"
-- "image           #image     #object #image     ilk( (the stage).image )"
-- "script instance #instance  #object #instance  ilk( new( script "ilkTest" ) )"
-- "xtra instance   #instance  #object #instance  ilk( new( xtra "fileIO" ) )"
-- "member          #member    #object #member    ilk( member(1) )"
-- "xtra            #xtra      #object #xtra      ilk( xtra("fileIO") )"
-- "script          #script    #object #script    ilk( script("ilkTest") )"
-- "castlib         #castLib   #object #castLib   ilk( castlib(1) )"
-- "sprite          #sprite    #object #sprite    ilk( sprite(1) )"
-- "sound           #instance  #object #instance  ilk( sound(1) )"
-- "window          #window    #object #window    ilk( the stage )"
-- "media           #media     #object #media     ilk( member("ilkTest").media )"
-- "timeout         #timeout   #object #timeout   ilk( timeout("A").new(1,#a)) )"
-- "void            #void      #void              ilk( VOID )"
-- "NAN             #float     #number #float     ilk( sqrt(-1) )"
-- "<Null>          #void      #void              ilk( call(#m, []) )"

<Null> is a strange beast, it is similar to VOID, but not quite, as the following will illustrate:

X = call(#m, [])
put X
-- <Null>
put X = VOID
-- 1
put ilk(X)
-- #void
put ilk(X, #void)
-- 1
put voidP(X)
-- 0

If there are any other types that ilk() reports, that I missed, let me know and I'll add them...

During the next documentation update, simply add any new types and/or thingsToTest into the appropriate lists, and run ilkTest again, it will actually use ilk() itself to generate a valid table for you, so we should be able to get this table fixed in the docs...

  1. Copy this script into a script castmember and name the member "ilkTest"
  2. Then run ilkTest in the message window...
on ilkTest
  thingsToTest = [:]
  thingsToTest.addProp( "integer", "128" )
  thingsToTest.addProp( "float", "128.128")
  thingsToTest.addProp( "string", QUOTE & "A String" & QUOTE)
  thingsToTest.addProp( "linear list", "[1,2,3]")
  thingsToTest.addProp( "property list", "[#A:1,#B:2]")
  thingsToTest.addProp( "rect", "rect(0,0,640,480)")
  thingsToTest.addProp( "point", "point(320,240)")
  thingsToTest.addProp( "color", "rgb(" & QUOTE & "#FFFFFF" & QUOTE & " )")
  thingsToTest.addProp( "date", "the systemDate")
  thingsToTest.addProp( "symbol", "#symbol")
  thingsToTest.addProp( "picture", "(the stage)Picture")
  thingsToTest.addProp( "image", "(the stage)Image")
  thingsToTest.addProp( "script instance", \
      "new( script " & QUOTE & "ilkTest" & QUOTE & " )")
  thingsToTest.addProp( "xtra instance", \
      "new( xtra " & QUOTE & "fileIO" & QUOTE & " )")
  thingsToTest.addProp( "member", "member(1)")
  thingsToTest.addProp( "xtra", "xtra(" & QUOTE & "fileIO" & QUOTE & ")")
  thingsToTest.addProp( "script", "script(" & QUOTE & "ilkTest" & QUOTE & ")")
  thingsToTest.addProp( "castlib", "castlib(1)")
  thingsToTest.addProp( "sprite", "sprite(1)")
  thingsToTest.addProp( "sound", "sound(1)")
  thingsToTest.addProp( "window", "the stage")
  thingsToTest.addProp( "media", \
      "member(" & QUOTE & "ilkTest" & QUOTE & ")Media")
  thingsToTest.addProp( "timeout", \
      "timeout(" & QUOTE & "A" & QUOTE & ")New(1,#a))")
  thingsToTest.addProp( "void", "VOID")
  thingsToTest.addProp( "NAN", "sqrt(-1)")
  thingsToTest.addProp( "", "call(#m, [])")
  ilkTypes = [ \
               #object, #instance, #script, #xtra, \
               #member, #castlib, #sprite, #sound, #window, #media, \
               #timeout, #image, #picture, \
               #list, #linearlist, #proplist, \
               #number, #integer, #float, \
               #string, \
               #rect, #point, #color, #date, \
               #symbol, #void \
  put pad( "X=", 16 ) & pad( "ilk(X)", 10 ) && \
      pad( "ilk(X,Type) = 1", 18 ) && "Example"
  put EMPTY
  repeat with n = 1 to thingsToTest.count()
    outputString = pad( thingsToTest.getPropAt(n), 16 ) 
    put "#" & pad( string(ilk(value(thingsToTest[n]))), 9 ) \
         after outputString
    validTypes = EMPTY
    repeat with testType in ilkTypes
      if ilk( value(thingsToTest[n]), testType ) then 
        put "#" & testType & SPACE after validTypes
      end if
    end repeat
    put outputString && pad( validTypes, 18) && \
        "ilk(" && thingsToTest[n] && ")"
  end repeat


on pad stringToPad, paddedLength
  numSpaces = paddedLength - stringToPad.length
  repeat with n = 1 to numSpaces
    put SPACE after stringToPad
  end repeat
  return stringToPad

Hope it helps,

VOID vs. voidP() (Round 2)


Date: Feb. 8, 2002

> We beat each other to a pulp on another list in regards to this.

Hi Zav,

Yes we did... and it was fun... ;-)
I'm not trying to resurrect old battles though...

I was giving some tips to newbies about when to use the constant VOID and when to use the function voidP() instead. The fact (for good or ill) that VOID is equal to 0, diminishes it's use as a tester for a real void condition. It can lead to difficult to debug issues, if it catches a newbie off guard.

One very important use for testing for a void condition is to validate a function or handler's input parameters and set defaults. If you use the constant VOID for such a case, like so:

on doSomething x, y
   if x = VOID then x = 320 -- set default
   if y = VOID then y = 240 -- set default
   put "x =" && x
   put "y =" && y
end doSomething

It would work for nonzero and/or void parameters as follows:

doSomething 10, 20
-- "x = 10"
-- "y = 20"

-- "x = 320"
-- "y = 240"

You'd run into trouble if zero were passed to doSomething in x or y, like so:

doSomething 0, 0
-- "x = 320"
-- "y = 240"

In that instance you surely don't want the values changed because the parameters are not really void. They have a set value and that value is zero.

If instead you always test for a void condition this way:

on doSomething x, y
   if voidP( x ) then x = 320 -- set default
   if voidP( y ) then y = 240 -- set default
   put "x =" && x
   put "y =" && y
end doSomething

You won't have any trouble...

doSomething 10, 20
-- "x = 10"
-- "y = 20"

-- "x = 320"
-- "y = 240"

doSomething 0, 0
-- "x = 0"
-- "y = 0"

The docs completely miss this subtle difference and suggest using the constant VOID to test for a void condition, when voidP() would be more suited to such a test.

So, I can further boil my rules of thumb down to two:

1) If you are interested in TESTING for a void condition, use voidP() rather than the constant VOID.

if voidP( someVariable ) then someVariable = 10 -- set to a default value

Or you could also use ilk() since we got all the old ilk() bugs cleaned up and it is now presentable, since D7.0.2.

if ilk( someVariable, #void ) then someVariable = 10 -- set to a default value

2) If you are trying to SET a variable to be void, then use the constant VOID.

someVariable = VOID -- we are all done with it

Following those simple rules, avoids the entire issue...

The example in the Lingo dictionary on page: 539

if currentVariable = VOID then
   put "This variable has no value"
end if

is incorrect, the variable has no value OR the value zero. So it could be rewritten as I suggested previously:

if currentVariable = VOID then
   put "This variable has no value, or is equal to zero"
end if

But that's really not the best use of the constant VOID anyway. The best use for it is to SET a variable to VOID. voidP() is better for testing for a void condition.

So I'd suggest changing the examples in the Lingo dictionary on pages 539 and 540 to the examples I used in my two rules of thumb above.

It would also help newbies immensely if this subtle difference between VOID and voidP() were mentioned in the Lingo dictionary, which it's not, which is why I'm discussing it here...

Of course experienced Lingo programmers may "break" my suggested rules of thumb for specific purposes. I'm sure some people out there are indeed using VOID as a test (to test for a void OR 0 condition, such as when you expect an object and want to be sure it's not void or 0), but I'm sure they also understand the subtle issue involved, and all its potential ramifications. My tips are obviously not absolute, but I think they will help newbies avoid potentially thorny issues. It's for the newbies that I bring these subtleties up...

Besides, it gives me something interesting to think about, while I have my morning coffee and warm up my synapses for the day... ;-)


VOID vs. voidP()


Date: Feb. 7, 2002

One quick follow up on the constant VOID...

I'd add one more rule of thumb to my previous two...

1) If you are testing to see if something is defined, don't use the constant VOID, instead use the Lingo function voidP() (or ilk()) which WILL determine if something is really defined or not.

put voidP( z )
-- 1

2) If you are testing for something that could be void or zero, then test for zero not the constant VOID. Personally, Lingo's VOID constant is not very useful for testing if a variable is void or not, because it's also equivalent to zero.

The following can lead to debugging issues.

z = 0
put z = VOID
-- 1

3) If you need to SET a variable to be void, that is really the best use for the constant VOID.

z = VOID
put voidP( z )
-- 1
put ilk( z )
-- #void


The value of VOID...


Date: Feb. 7, 2002

I've always felt that Lingo's use of the constant VOID is a little bit too "loose" (since it's equal to 0). Here are some examples to be aware of...

put value( "xyz" )
-- <Void>

The string has no value so it's considered void.


put value( "0" )
-- 0

The string has the value zero.


put value( EMPTY )
-- 0

Personally I would say the string has no value and should be considered void, just like "xyz", but Lingo considers it zero, which can lead to confusion.


put VOID = 0
-- 1

Lingo considers void to be equal to zero, this can lead to all types of confusion if you're not careful. Consider this example...

put value( "0" ) = value( "xyz" )
-- 1

You obviously wouldn't be writing such a statement, but if you are comparing the value of two variables instead, it could arise, leading to debugging issues...

So, what does this all mean for the typical Lingo programmer?
You'll avoid much confusion if you use two rules of thumb.

1) If you are testing to see if something is defined, don't use the constant VOID, instead use the Lingo function voidP() (or ilk()) which WILL determine if something is really defined or not.

2) If you are testing for something that could be zero, then test for zero not the constant VOID. Personally, Lingo's VOID constant is rendered mostly useless for testing if a value is defined (or at the least, dangerous) by it's equivalence to the integer zero. IMHO ;-)

Even the 8.5 Lingo dictionary is incorrect on page: 539 Which shows that even those writing the manual missed this subtle distinction which can lead to difficult to debug problems.

The following example is incorrect:

if currentVariable = VOID then
   put "This variable has no value"
end if

and should be rewritten as follows:

if currentVariable = VOID then
   put "This variable has no value, or is equal to zero"
end if

Try this on an undefined variable:

put x = VOID
-- 1

Now define the variable as zero and try again:

x = 0
put x = VOID
-- 1

Now have some real fun and compare the defined variable x to another undefined variable:

put x = BOGUS
-- 1

What is happening is that the value of an undefined variable is interpreted as being equal to zero. Since the constant VOID is little more than an undefined variable, it is interpreted as being equal to zero. Therefore, I personally see no use for the constant VOID for testing, and would simply use zero myself in such an instance.

Since, the constant VOID is not very useful for testing if a variable has a value or not, I'd suggest changing the example in the Lingo dictionary entirely, and instead use VOID to set the value of a variable to VOID. This is the best use of the constant VOID. So a better example would be:

someVariable = VOID


The only way to reliably test for an undefined value is with the Lingo function voidP() (or ilk()) as follows:

Test an undefined variable:

put voidP( y )
-- 1
put ilk( y, #void)
-- 1
put ilk( y )
-- #void

Now define the variable as zero and try again:

y = 0
put voidP( y )
-- 0

This difference between VOID and voidP() can lead to logical conundrums if used for testing, such as this:

y = 0
put ( y = VOID ) AND ( voidP( y ) )
-- 0

y is equal to the constant VOID, but it's not REALLY void... ;-)


D6 actorList Rock Solid


Date: Aug. 6, 1997

Hi Andrew,

I just ran some tests. I ran the enclosed "actorList test" in Director 4, 5 & 6 on the Mac.

Director 4 bombs after a short while.

Director 5 does not bomb. But then if I stop the movie and quit Director 5 (without emptying the actorList), it does bomb with a type 2 error.

Director 6 seems rock solid. So it looks like the problems with the actorList may become an issue of the past. Maybe Macromedia implemented some of the buffering techniques that us and others had posted to Direct-L in the past.

Feel free to run the following test in each version of Director from 4-6. Just open the message window and start the movie. It randomly births objects into the actorList, each of which has a random life span and then commits suicide... ;-)


Here are the scripts for a simple test movie:

-- movie script
on startmovie
  global gObjectNum
  set gObjectNum = 0
  set the actorList = []

-- frame script, place in frame 1
on exitFrame
  if random( 10 ) then add the actorList, birth( script"object" )
  go to the frame

-- parent script must be named "object"
property myStep, myNum, myLife

on birth me
  global gObjectNum
  set gObjectNum = gObjectNum + 1
  set myNum = gObjectNum
  set myStep = 0
  set myLife = random( 50 )
  put "birthing: Object #" & myNum
  return me

on stepframe me
  set myStep = myStep + 1
  if myStep >= myLife then deleteMe( me )

on deleteMe me
  set whichNum = getPos( the actorList, me )
  put "***DELETING: Object #" && myNum
  deleteAt the actorList, whichNum

Incremental Processing


Date: Feb. 13, 1997

>My logic was that if I birthed another object, it
>would go on it's merry way and be independant of
>any other object. Instead, it seems that the method
>I'm using still makes for very linear logic flow.

In order for an object to "go on it's merry way" you must make sure you are giving it control incrementally to update itself and do its stuff...

One way to do this is to give the object an on stepFrame handler and then put a pointer of the object on the actorList. Then each time the stage is updated the object will be given a chance to update itself. Think in terms of small bite sized actions rather than continuous action.

To have animations work while other things are happening you need to program a little differently than you would otherwise. You must break all actions down to small increments that can keep track of where they are and where they are going. One way to acheive this is through LingOOP.

Hope that points you in the right direction.


Never Use the actorList! NOT!


Date: Jan. 2, 1997

I wouldn't quite make such a blanket statement as "NEVER USE the ACTORLIST!" myself.

Yes, uncontrolled use of the actorList can lead to problems. Most notably from putting master copies of objects on the list that delete themselves from the list during a stepframe handler. This is because you can't change the list itself during the loop that is processing it or you risk having the loop run past the end etc... therefore it's far from bulletproof.

The actorlist as implemented does have uses though.

If you are using simple objects that only need to animate for specific time frames you can safely add them to the list and delete them from the list from other handlers such as frame handlers. Just don't do it from a stepframe or a handler called from a stepframe.

I also wouldn't suggest putting your "master" objects on the actorlist. We keep all master objects elsewhere and simply put a pointer to the object on the list.

What do I mean by "master" object? Simply the first pointer to the object that is used to hold the object itself and keep it in memory. Then adding this master pointer to the actorList will actually only create a second, temporary pointer to the master object itself. Then deleting this pointer from the list will not "destroy" the object since the master pointer is elsewhere.

If you need more robust use of the actorList then I would suggest implementing your own managed list similar to the "activeActors" and "deletedActors" list mechanism I had posted in the past. I also posted an analogy "the shopping excursion" that helped explain the concepts of simply using the actorlist as a queue in more depth.


Performance and the actorList


Date: Nov. 20, 1996

>In such cases, every object on the
>actorList gets sent a stepFrame message every iteration through the
>loop--unnecessary code executes in a critical loop, resulting in a
>performance hit.

Yes, that's why you should only put items on the actor list or your own internal activeActors list only when they have real tasks to perform. By only putting objects on the list that are currently animating, you can target all the processing exactly where it needs to go.

Items that are simply sitting on the screen waiting for mouseclicks should NOT be sitting on the actorlist. We usually keep them in their own control lists. We keep a global sprite list and when an object is activated for a screen control like a button, it puts its pointer into the global sprite list. Then all mousedown and mouseup messages are passed directly to the object by indexing into the sprite list. We don't put these types of objects in the activeActors list.

So I don't necessarily agree that the actorlist (or an internal custom activeActors List) should be avoided, only that it should be properly managed and used in conjunction with other control structures. Just don't try to do everything in the actor list and don't put pointers to items in the activeActors list that don't currently need to receive stepframes.


The Shopping Excursion


Date: Nov. 11, 1996

Let me clarify a concept that may not have been clear in my last post.

When I add or delete actors from the active objects lists, I am only adding or deleting pointers from the lists. The objects themselves remain happily alive and able to go about their business as they see fit. (since their master pointers reside elsewhere)

Think of it this way.

People go into the supermarket. (objects being birthed into their master list) They may be comunicating with each other and doing different things.

Now some of them go to the meat counter and put their name on a list. Well an object putting itself on the active objects list is just like this list. The object can still do other things since it has only taken a request to be called in turn.

Now lets say the person gets its turn at the counter. Well, when the person is done, it's name is crossed off the list since it is no longer waiting to be called. This crossing off the list is the same as deleting the pointer in the active objects list. It does not destroy the object itself since the object's master pointer is elsewhere in another list or a global variable etc. No more than the person is deleted from the supermarket. The person is not deleted from the supermarket until it leaves the market. The object is not deleted from memory until ALL pointers to it are deleted.

I only use the activeObjects list as a temporary queue for objects to recevie stepframes. I don't use it to hold the master pointer to objects. Otherwise it's like saying anytime someone enters the supermarket they must proceed directly to the meat counter and put their name in, and wait there without doing anything else. Then when their turn is done they are thrown out of the store... Now that's not very nice is it? Not very flexible either.. ;-)

So we are not really shuffling objects around from list to list as it may seem. We have objects that already exist as buttons in a buttonList within a control structure. (the supermarket) When the objects need servicing they just put a pointer to themselves on the active objects list. (the meat counter)

Quite simple if you think of it this way... I hope... ;-)

Did we all enjoy our little shopping excursion?


A Managed actorList


Date: Nov. 14, 1996

>Sounds great. My button object is still evolving and looking through your
>post, a couple of questions occur to me.
>Your gTheMovieMan object is in the actorList so it receives stepFrames. The
>actorObjects you are adding, are they ancestors of gTheMovieMan? If so then
>an ancestor of an object in the actorList also receives stepframes? I'll
>have to check this myself.

No need for ancestors here. Ancestors are used to provide a heirarchy of methods and properties. Such as defining an animal ancestor with an eat method and then creating a fish decendent and a bird decendent. Both the bird and the fish may eat the same way but the bird will have a fly method where the fish will have a swim method.

What we do for the active actors is this...

We birth our movie manager object into a global variable called gTheMovieMan. We then immediately put this on the "real" actorList. This is the only object we actually put on the true actorList. Note: the global variable is used as the master pointer to this object. The pointer on the actorList is a secondary temporary pointer to the object. Therefore deleting it from the list does NOT remove the entire object from memory... use the same approach for any objects put onto the active actors list.

The movie manager object has property variables and methods of it's own used throughout any subsequent movies. They remain accessible through the global variable. These methods are used to control all generic movie functions such as reading and writing to files, User and Prefs files, Checking Memory, Checking screen depth, Checking the machine that you're running on, Setting and resetting screen depth on a Mac, etc.

One of the most important features we build in is a managed actorList of our own. We use two lists that are internal to the movie manager object: myActiveActors and myDeleteActors. (As a convention I use 'g' to signify a global variable and 'my' to signify a property variable of an object. I also use plural names to signify lists and "The" to indicate an object.)

>Also, how do you check if one object is also in another list? Previous
>posts refer to some inconsistencies regarding ojbect equality.

So when gTheMovieMan receives a stepframe, it checks to see if anything is on the myDeletedActors list. If there is, then each is removed from both the myDeletedActors and myActiveActors list. These are located on each list (with getPos) and then truely deleted from the lists (with DeleteAt).

  -- first delete any objects waiting to be deleted from the active list
  repeat with i = count( myDeletedObjects ) down to 1
     -- find object to dump
    set location to getPos( myActiveObjects, getAt( myDeletedObjects, i ) )
    deleteAt( myActiveObjects, location ) -- delete object from active list
    deleteAt( myDeletedObjects, i )       -- delete object from deleted list
  end repeat

Then a stepframe is passed to each of the items remaining on the myActiveActors list. This way objects are deleted BEFORE going into the stepframe loop. If an item is told to delete itself during the stepframe loop, it will actually be removed just BEFORE the NEXT stepframe loop.

  -- now pass the stepFrame to each object in the active list
  repeat with i = count( myActiveObjects ) down to 1
    stepFrame( getAt( myActiveObjects, i ) )
  end repeat

>When you delete an ojbect from the deletedActors list do you totally delete
>it, ie set ? = gVoid ? or do you shuffle it to an inActiveActors list to
>hide it from stepFrames temporalily. The reason I ask is because with my
>button object I don't want to rebirth a button I only wanted to make it
>inactive while showing a certain "state" on screen, ie a director
>fabricated dialog box. This is where my gProcessStepFrame global came into

We delete it from the active actors list but not from existance.

I would suggest using some other list to manage your list of buttons. Only use the actor list as a temporary place to hold items waiting for stepframes. What we do is we have a controlStrip object that is responsible for holding all the buttons in a control area. Then when the controlStrip is activated each individual button puts itself onto the active list by issuing:

addActor( gTheMovieMan, me )

When the controlStrip is deactivated then each button pulls itself off the list with this command:

deleteActor( gTheMovieMan, me )

Here are some sample methods we use in the movie manager that process add and delete actor requests.

on showActors me
  -- used for debugging...

  put "the actorList =" && the actorList
  put "myActiveObjects =" && myActiveObjects
  put "myDeletedObjects =" && myDeletedObjects


on clearActors me
  -- used to clear both lists don't use in a stepframe.
  -- if in a stepframe you may deleteActor, not clearActors...

  set myActiveObjects to []
  set myDeletedObjects to []


on addActor me, whichObject
  if getPos( myActiveObjects, whichObject ) = 0 then 
    -- not already in the active list
    add( myActiveObjects, whichObject )
  end if
  set location to getPos( myDeletedObjects, whichObject ) 
  -- see if it was marked for deletion
  if NOT location = 0 then -- was marked for deletion
    deleteAt( myDeletedObjects, location ) 
    -- since it is being reactivated, take it off deleted list
  end if
  -showActors me -- uncomment for debugging


on deleteActor me, whichObject
  set location to getPos( myActiveObjects, whichObject )
  if NOT location = 0 then 
    -- be sure it is in the ACTIVE list before deleting
    if getPos( myDeletedObjects, whichObject ) = 0 then 
      -- not already in the DELETED list
      add( myDeletedObjects, whichObject )
    end if
  end if  
  --showActors me -- uncomment for debugging


That's about it. Hope this helps...



Managing the actorList


Date: Nov. 13, 1996

>Instead of setting the actorList = [], I am doing a "setAt the actorList,
>position, 0" in a repeat loop and the GPF's vanished. I have to do this on
>quiting as well or else another GPF.
>Others have mentioned that birthing straight into the actorList is not a
>good idea but I've been doing this without incident for my  button objects
>and it appears clean in 16 bit.

We use a two step process when accessing the ActorList...

Since the ActorList can be the cause of crashes if objects are pulled off them during stepframes etc. we use our own simulated actorlist.

We birth our movieManager object onto the actorlist when our first movie starts up. Then our movieManager has methods for addActor and deleteActor. These will add and delete actors to our internal custom activeActors list which is our managed version of the actorlist.

The addActor method checks to be sure an object is not already on the activeActors list and then adds it.

The deleteActor method checks to be sure an object is actually on the activeActors list (and not already on the deleteActors list) before enabling a delete. If enabled the deleteActor method adds the object to be deleted to our deletedActors list.

Then on the stepframe, before passing a stepframe to the activeActors list we first check the deletedActors list and remove any objects that are in the deletedActors list from both lists.

This way when our stepframes are actually processed through the activeActors list the objects are insulated from being pulled off the list during the stepFrame. If an attempt is made to delete an object during a stepframe, it won't actually be deleted until the NEXT stepframe.

This approach is actually much easier than it may sound. Once it's set up we can then easily add and remove actors from any object by issuing a single command without regard to if we are currently in a stepframe or not.

addActor( gTheMovieMan, actorObject )
deleteActor( gTheMovieMan, actorObject )

By managing the list yourself you can save many headaches...


DreamLight’s activeObjects:
Precursor to the actorList


Date: 1992

Before there was an official actorList, we had implemented an object update mechanism in Director 3's factories. We passed our own mNextFrame message to each object within a managed stepMovie stack. Objects could freely push themselves onto and pop themselves off of this stack. This little bit of code showed us the future of Director and strikingly similar functionality was built into Director 4's actorList. However, our old activeObjects list was bullet proof in 1992 where Director's own actorList didn't become bullet proof until 1997... ;-)

This actual code is obsolete and not fully optimized, but the concepts are the same as the newer parent child objects and today's actorList. This code, from DreamLight Verttice, was included on Macromedia's first Authorized Developer CD-ROM. I have posted it here for your enjoyment at peering into the past. It may also give you some ideas for your own managed lists. The makeStack factory is also available in the DreamLight Verttice Insight. Check out the OOP photon factory to see how an object hopped on and off TheActiveObjects stack and how it animated itself.

-- Object: handlers (Movie Script)
-- (C) 1992 DreamLight(R) Incorporated

on startMovie
  global mode, theActiveObjects, theKeyChecker, nextAction, vertticeLocked
  set the stageColor = 0
  set the exitLock = TRUE
  set mode = "StartUp"
  --set vertticeLocked = TRUE
  set nextAction = "nothing"
  set theActiveObjects = makeStack(mNew, False, theActiveObjects)
  set theKeyChecker = makeKeyChecker(mNew, theKeyChecker)
  when keyDown then doKeyDown
  when mouseDown then doMouseDown
  when mouseUp then doMouseUp
end startMovie


on stepMovie
  global theActiveObjects, nextAction
  if nextAction <> "nothing" then
    do nextAction
    if nextAction <> "doWinLattice" AND¬
       nextAction <> "doWinLevel" AND¬
       nextAction <> "doStartLevel" then exit
  end if
  --put "stepMovie: " & the frame
  repeat with i = 1 to theActiveObjects(mGetLength)
    set theActiveObject = theActiveObjects(mGet, i)
    --put i && theActiveObjects(mGetLength) && theActiveObject(mName)
  end repeat
end stepMovie


on stopMovie
  global theActiveObjects, oldColorDepth
  set theActiveObjects = dumpObject(theActiveObjects)
  set the colorDepth = oldColorDepth
end stopMovie


on activeObjectsDone
  global theActiveObjects
  if theActiveObjects(mGetLength) = 0 then return True
  else return False
end activeObjectsDone


on activateObject whichObject
  -- pushes object onto the active stack for nextframe processing
  global theActiveObjects
  theActiveObjects(mPush, whichObject)
end activateObject


on deActivateObject whichObject
  -- locates and removes object from the active stack
  global theActiveObjects
  repeat with i = 1 to theActiveObjects(mGetLength)
    if theActiveObjects(mGet, i) = whichObject then -- object found
      theActiveObjects(mRemove, i)
      exit repeat -- done
    end if
  end repeat
end deActivateObject


on setUpSprite whichSprite, whichObject
  activateSprite(whichSprite, whichObject)
end setUpSprite


on activateSprite whichSprite, whichObject
  -- inserts object into the sprite stack to control the channel
  global theSprites
  if objectP(theSprites) then theSprites(mPut, whichSprite, whichObject)
  puppetSprite whichSprite, True
end activateSprite


on deActivateSprite whichSprite
  -- clears object from sprite stack
  global theSprites
  if objectP(theSprites) then theSprites(mPut, whichSprite, 0)
  puppetSprite whichSprite, False
end deActivateSprite


on dumpObject whichObject
  -- releases and disposes of an object
  if objectP(whichObject) then
  end if
  return whichObject -- pass back empty object pointer
end dumpObject


BlastOff! The Award-winning 3D Animated Short film by Michael Scaramozzino - Special Edition DVD

Please Support Our Continuing Independent Film Making Efforts!
Order your Award-winning BlastOff! Special Edition DVD today!

BlastOff!™ Merchandise Available @ Telebites.com BlastOff! T-Shirts BlastOff! Hats BlastOff! Mugs BlastOff! Calendar, Prints & Posters BlastOff! Mousepads

Silver Sage Scrolls™ inspiration through the ages Available @ Telebites.com

To view this site properly, please upgrade to a browser that supports current Web standards.


BlastOff! Wins a Silver W3 Award in the Pioneering Category of Web Video - 3D Animation

BlastOff! Wins an Official Honoree Webby Award in the category of 3D Animation

























































































DreamLight Incorporated, 323 Andover Street, Suite 6, Wilmington, MA 01887 USA, Telephone: 978-658-5110
Search/Index Top Help