DreamLight Interactive

DreamLight Director Talisman

DreamLight.com

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

Raising Well-behaved Sprites, Lingo Sprite Behaviors & Other DreamLight Director Talisman, Tips & Tricks

Previous Contents Next

Behaviors are really not something entirely new as you might expect. They are nothing more than a simplified way to use parent/child objects. When a sprite begins, Lingo automatically creates a child instance of the behavior script just as it would for a parent script. In the case of a behavior it automatically puppets the sprite, creates a property variable for the object called “spriteNum” and initializes it to the number of the sprite channel. This new object instance is then stored in an internal list of sprites. This behavior object receives some new messages such as BeginSprite, and you can send it messages with SendSprite. In most other respects it operates much as a normal child object operates.

We use sprite behaviors for everything from our developer utilities such as DreamLight RAMLight through full-length CD-ROM projects such as the award-winning KeyQuest edutainment CD-ROM, to our on-line entertainment products like Quipples: The Internet game show of satirical riddles.

This page also includes some miscellaneous bugs, tips & tricks not directly related to behaviors.

Enjoy,

Michael Scaramozzino

Michael Scaramozzino
President and Creative Director

DreamLight Director Talisman
Director Tips & Tricks

Authorized Macromedia Developer

Contents

Top

The Number of the Beast, (Frame Script Sprite)

Top

Date: Feb. 20, 2002
(Condensed from my somewhat lengthy discussion about this issue on Wish-Director)

What is the number of the frame script sprite (channel)?
Well, it depends exactly who you ask and exactly when you ask.

First, let me outline how to currently (as of D8.5.1) get a grasp on this slippery beast in Lingo. There are three different values used to indicate the frame script channel depending on how you ask and from where you ask. They are as follows:

  1. Inside a frame script behavior, the value of the currentSpriteNum is 0.
  2. Inside a frame script behavior, the value of Me.spriteNum is -5.
  3. Inside a frame script behavior's isOkToAttach handler, the sprite number argument is 1.

I have personally found that referring to the frame script sprite number by using the currentSpriteNum (which is 0 in a frame script) is currently the best way to refer to a frame script sprite in a behavior, especially since it's the only valid way to access any of the sprites properties via Lingo as you'll see below. (Though you can only access a couple of Director's built in properties for it this way) Currently, in an isOKTattach handler though, you can't use the passed sprite number since the number 1 could easily be mistaken as graphic sprite number 1, so you have to rely on the type argument instead. It would obviously be much more consistent if all three of these access methods used the same number to refer to the frame script channel.

Now, let me outline the case I made to Macromedia to fix this problem by changing Me.spriteNum and the sprite number argument in an isOKToAttach handler, both to also return 0 for the frame script sprite.

Since the original definition of a sprite in Director, going way back, was that of an animated graphic, the script channel was not "really" considered a "sprite" and thus the spriteNum of the frame script channel has always been considered "ill defined". In the current implementation of Director, using behaviors, the frame script channel has much more in common with what Director now considers sprites than it used to. So much so in fact that it would be much more consistent and easier to program if the frame script channel were fully promoted to sprite(0), as it already partially is considered by Lingo, as you'll see below.

  1. The frame script channel uses sprite behaviors which are attached to it, just like they are to graphic channels, they may span a range of frames just like other sprites. They are written and attached exactly as they are for other channels.
  2. The frame script channel receives the following sprite behavior messages: beginSprite, endSprite.
  3. You can send a frame script behavior messages using sendSprite( 0, #message )
  4. The frame script channel also has properties of sprite(X).startFrame and sprite(X).endFrame.
  5. The frame script channel also has properties of sprite(X).scriptInstanceList
  6. To access a frame script sprite's startFrame, endFrame and scriptInstanceList properties, you must use zero... You can't use -5 (startFrame & endFrame will generate script errors, and scriptInstanceList will return 0) and you can't use 1 which really refers to the graphic sprite number 1... These must be accessed as sprite(0), only, so IMHO the spriteNum (and attachedSpriteNum) should be 0 as well for frame script sprites...

So, even though Lingo currently uses three different numbers to refer to the frame script channel ( 0, -5, and 1 ) it only allows access to any of the sprite's properties if you use 0, which corresponds to the currentSpriteNum. If you attach the following behavior to a graphic sprite and the frame script sprite (spanning a different range of frames) and run the movie you'll see what I mean... also, while it's running use sendSprite(0,#report) to send a custom message to the copy running in the frame script.

property spriteNum, pSprite, pSpriteName

on beginSprite Me
  Me.pSpriteName = "sprite(" & the currentSpriteNum & ")"
  Me.pSprite = sprite( the currentSpriteNum )
  Me.report()
end

on report Me
  put "sprite( the currentSpriteNum ) =" && \
      "sprite(" & the currentSpriteNum & ")"
  put Me.pSpriteName & ".startFrame =" && Me.pSprite.startFrame
  put Me.pSpriteName & ".endFrame =" && Me.pSprite.endFrame
  put Me.pSpriteName & ".scriptInstanceList =" && \
      Me.pSprite.scriptInstanceList
  put "Me.spriteNum =" && Me.spriteNum
  put RETURN
end

-- "sprite( the currentSpriteNum ) = sprite(1)"
-- "sprite(1).startFrame = 1"
-- "sprite(1).endFrame = 28"
-- "sprite(1).scriptInstanceList = [<offspring "SpriteBehavior" 3 146e8058>]"
-- "Me.spriteNum = 1"
-- "
"
-- "sprite( the currentSpriteNum ) = sprite(0)"
-- "sprite(0).startFrame = 5"
-- "sprite(0).endFrame = 8"
-- "sprite(0).scriptInstanceList = [<offspring "SpriteBehavior" 3 146e2788>]"
-- "Me.spriteNum = -5"
-- "
"

If you edit the above script to use Me.spriteNum instead of the currentSpriteNum, it will only work on the graphic sprite, not the frame script sprite...

The primary argument against changing this, is that some people have been using Me.spriteNum = -5 to detect a sprite behavior running as a frame script. I don't recall Me.spriteNum = -5 being documented or supported but I do recall the currentSpriteNum = 0 being both documented and supported to detect a sprite behavior running as a frame script. Therefore, changing Me.spriteNum to also return 0 for a frame script sprite sounds entirely reasonable to me. If the frame script channel were promoted to sprite(0) we could use the spriteNum to access its properties just like in other sprites.

-MikeS

Using isOKToAttach in your behaviors...

Top

Date: Feb. 1, 2002 (Updated Mar, 12, 2002)

isOKToAttach Lingo Dictionary. Pg. 252

The example will not work as written, if the user uses the suggested convention of including the line

property spriteNum

to explicitly declare the automatic sprite property spriteNum. As shown on page 475.

Attach this behavior to a sprite and you'll see what I mean:

property spriteNum -- automatically set when instanced

on isOKToAttach Me, spriteType, spriteNum
  beep
  put EMPTY
  put "isOKToAttach:"
  put "spriteNum =" && spriteNum

  return TRUE
end

You'll see this in the message window:

-- ""
-- "isOKToAttach:"
-- "spriteNum = "

In this case Lingo uses the declared property spriteNum inside the isOKToAttach handler (rather than the sprite number passed to isOKToAttach) and at the time that the handler is actually called, the property "spriteNum" is not defined and is VOID. spriteNum only gets set when the behavior is actually instanced, during run time, so the test will not work as expected.

Instead you should use a different variable name, rather than spriteNum in your isOKToAttach handler. Something like attachedSpriteNum or aSpriteNum will work fine. The example would also work if you don't explicitly declare spriteNum as a property in the behavior. Explicit declaration is optional, but personally I would recommend declaring it, since it makes the code easier to understand to someone who may not be a Lingo expert.

D8.5.1 isOKToAttach BUG

The Lingo Dictionary also states that isOKToAttach handler is only called once, when a behavior is first attached to a sprite or script channel. There is a bug in D8.5.1 where every isOKToAttach handler, of every behavior, is also called multiple times in certain cases when the behavior tab of the property inspector or the behavior inspector is brought to the foreground with any sprite selected.

Steps to reproduce

  1. Create a new movie in D8.5.1
  2. Paste this script into a new script cast member
on isOKToAttach Me, aSpriteType, aSpriteNum
  
  beep
  put EMPTY
  put "isOKToAttach:"
  put "aSpriteType =" && aSpriteType
  put "aSpriteNum =" && aSpriteNum

  return TRUE
  
end
  1. Set the script's type to a behavior
  2. Create a rectangle on the stage
    (DONT ATTACH THE BEHAVIOR TO IT)
    (LEAVE THE RECTANGLE SELECTED ON THE STAGE)
  3. Open the behavior inspector
  4. Click the "+" pop up and release it. You should hear one beep
  5. Open the message window and you should see the following.
-- Welcome to Director --
-- ""
-- "isOKToAttach:"
-- "aSpriteType = graphic"
-- "aSpriteNum = 1" 
  1. Bring the behavior inspector back to the foreground

Now you'll get multiple beeps and multiple sets of info appearing in the message window. Now any time you switch to another window and then bring the behavior inspector back to the foreground, isOkToAttach will run multiple times. Therefore you may want to avoid putting alerts, beeps, or other similar statements in an IsOKToAttach handler, since they may be called often, when you may not expect them to be.

Thanks,
-MikeS

A Pause for X seconds Behavior

Top

Date: Jan. 31, 2002

Here's a simple frame behavior you can use to loop in the current frame for a specified number of seconds...

-- Description

on getBehaviorDescription Me
  return \
"DreamLightš LoopFrame Frame Behavior" & RETURN & \
"© 2001 DreamLight Incorporated.  DreamLight.com" & RETURN & \
"-----------------------------------------------" & RETURN & \
"DESCRIPTION:" & RETURN & \
"Attach to a frame script to loop for the specified number of seconds." && \
"Then goes to the next frame when time is up." & RETURN & \
                RETURN & \
"PARAMETERS:" & RETURN & \
"¥ Seconds: Number of seconds to wait, set to zero to wait forever."
end

on getBehaviorTooltip Me
  return \
"Attach to a frame script to loop in the frame for X seconds."
end

on isOKToAttach Me, attachSpriteType, attachSpriteNum
  return attachSpriteType = #script -- ONLY works as a frame script
end

-- Property Variables

property seconds      -- number of seconds to loop, set to 0 to loop forever
property waitTicks    -- number of ticks wait for to loop

on getPropertyDescriptionList Me
  return [ \
      #seconds: [ #comment:  "Loop for how many seconds?:", \
                      #format:  #integer, \
                     #default:  1 ] \
  ]
end

-- Sprite Handlers

on beginSprite Me
  Me.waitTicks = the ticks + (Me.seconds * 60)
end

on exitFrame Me
  if (Me.seconds = 0) OR (the ticks <= Me.waitTicks) then go to the frame
end

Hope it helps,
-MikeS

A concatList Function to Combine Lists

Top

Date: Oct. 9, 2001

>Is there a simple way to combine two or more property lists into one
>"master" property list?

Here's a simple utility function you may use...

on concatLists list1, list2
  -- (C) 2001 DreamLight.com
  -- Returns list1 and list2 as concatenated list3
  
  if ilk(list1) <> ilk(list2) then
    alert( "concatLists: Type mismatch." )
    return VOID
  end if
  
  list3 = duplicate(list1)
  case ilk(list1) of
    #list:
      repeat with n = 1 to list2.count
        list3.append( list2[n] )
      end repeat
      
    #propList:
      repeat with n = 1 to list2.count
        list3.addProp( list2.getPropAt(n), list2[n] )
      end repeat
      
    otherwise:
      alert( "concatLists: Linear or property lists required." )
      return VOID
      
  end case
  return list3
  
end concatLists

--

Here's how you can use it, as seen in the message window...

-- Welcome to Director --
x = [ #one:1, #two:2 ]
y = [ #three:3, #four:4 ]

a = [ 1, 2, 3 ]
b = [ 4, 5, 6 ]

put concatLists( x, y )
-- [#one: 1, #two: 2, #three: 3, #four: 4]

put concatLists( a, b )
-- [1, 2, 3, 4, 5, 6]

--

We typically create utility handlers like this for common functions that we need to perform. Over time, we collect all these into utility scripts for use in subsequent projects. We have created simple collections for common list functions, string functions, etc...

For more complicated common uses, we create object oriented manager classes such as for memory management, sound management, etc...

Hope it helps,
-MikeS

Converting a String to a List

Top

Date: Jun. 13, 2001

i have a string that = "[CompanyOverview, Products, Programs, TopService]"
and i need to get it into a list that will look like this
["CompanyOverview", "Products", "Programs", "TopService"]

Here are two handlers that will do the job. If you build the string without any spaces, then you won't need the second handler... ;-)

Hope it helps,
-MikeS

--

on stringToList str
  -- converts a string like this: 
  -- "[CompanyOverview, Products, Programs, TopService]"
  -- into a list like this: 
  -- ["CompanyOverview", "Products", "Programs", "TopService"]
  
  -- Extract items from the string leaving behind the square brackets
  str = chars( str, 2, str.length - 1 )
  
  -- save old item delimiter in case it's used elsewhere
  -- this can be safely deleted if you know you're not changing or relying 
  -- on the itemDilimiter eleswhere in your program, since the default is ","
  oldDelimiter = the itemDelimiter
  the itemDelimiter = ","
  
  newList = [] -- create a new empty list
  repeat with n = 1 to str.item.count -- loop through the items
    -- add each item to the list, with any whitespace removed...
    newList.add( stripWhiteSpace(str.item[n]) ) 
  end repeat
  
  -- reset itemDelimiter to it's previous value
  the itemDelimiter = oldDelimiter

  -- return the list to the calling handler
  return newList
end

--

on stripWhiteSpace str
  -- remove any leading and/or trailing spaces from a string
  
  -- remove leading whitespace
  repeat while str.char[1] = SPACE
    delete char 1 of str
  end repeat
  
  -- remove trailing whitespace
  repeat while str.char[ str.length ] = SPACE
    delete char str.length of str
  end repeat
  
  return str
end

-- Use them this way...
strLst = "[  CompanyOverview, Products, Programs, TopService]"

put stringToList( strLst )
-- ["CompanyOverview", "Products", "Programs", "TopService"]  

Opening and Positioning a MIAW

Top

Date: Aug. 26, 2000

 > So, the rect problem is solved now, but it still draws
 > the MIAW on the screen before it moves it to the new loc.

I'm not sure what you're trying to do with the frameLabels, but myWin.open() inherently sets myWin.visible to TRUE. So you could set up the window first and then do myWin.open() when you want to see the window for the first time. Or you could build your code more flexibly to allow various scenarios.

Here's one simple example:

on initWin x, y
   global gWin

   gWin = window( "launch" )
   gWin.windowType = 2

   moveWin( x, y )
   gWin.open()
end initWin

--

on moveWin x, y
   global gWin

   winWidth = 800
   winHeight = 600

   gWin.rect = rect( x, y, x + winWidth, y + winHeight )
end moveWin

--

This way you could simply initialize and open the window like this:

initWin( the stageLeft + 190, the stageTop + 80 )

If you need to do some processing in the window that does require it to be opened before you see it, you could do something like this:

initWin( - 100000, - 100000 )
-- very far away incase there are other monitors, the Mac could have
-- up to six monitors and some may be above to the left, so make
-- sure your numbers are large enough to keep it from showing...

-- do whatever you like... then

moveWin(  the stageLeft + 190, the stageTop + 80 )

--

If you wanted to get even fancier, you could build an object to handle the window. If you make a windowHandler object generalized enough, you'd be able to reuse it in other projects that need to handle windows...

-MikeS

Pixel Doubling the Stage

Top

Date: Aug. 23, 2000

Automatically setting the user's display to the appropriate
resolution is not difficult, but has some drawbacks. For example,
we've found that some LCD projectors will not display QuickTime
movies at 800x600 (although the host computer screen is
simultaneously displaying it perfectly), but the movies work just
fine at a higher resolution. If we automatically set the resolution,
the user would be hosed.

Another option is to resize the stage itself up to fill the screen. We recently did this on DreamLight Verttice which was originally designed (in 1991) for 512 x 384. We check the user's screen size and if it's 1024 x 768 or larger, we double the stage size up to 1024 x 768 with the following code...

on stageSize whichSize
  -- whichSize is 1 for normal size or 2 for pixel doubling
  
  screenRect = (the desktopRectList)[1]
  
  stageSizes = [ rect(0,0,512,384), rect(0,0,1024,768) ]
  
  if whichSize <> 1 then -- use default
    if screenRect.right >= 1024 AND screenRect.bottom >= 768 then 
       whichSize = 2
    else whichSize = 1
  end if
  
  newRect = stageSizes[ whichSize ]
  
  (the stage).drawRect = newRect -- scale stage to size
  
  -- center stage on screen
  hOffset = integer( (screenRect.width - newRect.width) / 2.0 )
  vOffset = integer( (screenRect.height - newRect.height) / 2.0 )
  
  (the stage).Rect = offset( newRect, hOffset, vOffset )
end

Actually the code checks for 1 or anything else in which case it pixel doubles if it fits. This way it defaults to pixel double if it fits and we then let the user use command-1 and command-2 to change it themselves if they wish.

Try the DreamLight Verttice download edition to see it in action. http://DreamLight.com/webshop/entertainment/verttice.html

(Note: It's disabled in the Shockwave edition, so you need to download the off-line version for either the Mac or Windows to see the pixel doubling.)

puppetPalette & colorDepth Bugs

Top

Date: Aug. 11, 2000

I'm currently updating DreamLight Verttice in D7.0.2 to run in 8-bit and under current Shockwave players. It was originally written in D3 to run in 4-bit and no longer runs in Shockwave 7 or later, it used factories etc... ;-)

I've run into the following two Director bugs...

1) Changing 8-bit palettes in the score immediately shows the new palette while the stage still shows the previous picture (Tested on Mac). If you try to use fade to black or white, it changes the palette first, then fades to black or white and then fades to the new image. Not very useful. I've basically had to resort to doing a pixel dissolve to a black frame, changing the palette while on the black frame and then pixel dissolving to the new frame. Unfortunately pixel dissolves look crappy on the PC so this is not an optimal solution.

2) In a full screen projector under Win-98, Lingo can set the colordepth from 32 down to 8 bit (I need 8-bit so I can colorize the game board via the palettes). The depth does report as changed but the screen just goes black, and stays black, not too useful... ;-) (Tested on Win-98) So I've had to resort to telling the user to change it themselves under Windows and just quit. It works fine on the Mac though.

-MikeS

Re: The Rect of Window, Windows Bug, Suggestion

Top

Date: Jul. 10, 2000

If the window rect is going to be "translated" when I give it to a window, then it would make much more sense to me, if it were then "untranslated" by the same amount when given back to me.

Actually, the more I thought about this, why couldn't Director simply add the menu bar "above" the window rect? Much as the title bar is added above the window rect on the Mac? Then no translation of the rect itself would be necessary and the Lingo code:

set the rect of window "sample" to the rect of window "sample" 

would maintain it's logical integrity across operating systems and we'd have direct "unfutzed" access to the window content's rect on all systems. That would make the most sense to me...

We don't have to translate our content's rect on the Mac, even though the title bar is added, why should we have to translate our content's rect on Windows just because a menu bar may be added as well?

On the Mac if I do this:

set the rect of the stage to rect(0,0,100,100)

it translates it down, to account for the menu bar so that then...

put the rect of the stage
-- rect(0, 71, 100, 171)

But no matter what, this...

set savedRect to the rect of the stage
-- ...
set the rect of the stage to savedRect

will always return the window to wherever it was, translated or not...

Just food for thought for a future version of Director... The more you can maintain the logical integrity of Lingo itself, across systems, the better, IMHO... FWIW... ;-)

-MikeS

Re: The Rect of Window, Windows Bug

Top

Date: Jul. 10, 2000

>Under Windows in authoring, the stage rect is set based on the menu
>bar being inside the stage window, as it would be in a projector. In
>authoring though the menu bar appears at the top of the screen, and
>so the stage gets moved down by the height of the menu by mistake.

If I ask a window to give me it's rect, I would logically expect that I could then give that rect back to the same window later and it would return to its original position. That's just what it does on the Mac but on Windows it moves...

Ideally, the Lingo programmer should be insulated from such operating system kludginess. IMHO, this Lingo code:

set the rect of window "sample" to the rect of window "sample"   

should logically return a window to it's original position.

>You could either stop trying to set the rect every frame, or you
>could set the rect once, see how much it was wrong by, and then allow
>for that next time.

Of course I can hack around the problem. I created that sample code, not because I was really trying to set the rect to itself each frame, but simply to illustrate the illogical unsymmetrical handling of the window rect on Windows.

If the window rect is going to be "translated" when I give it to a window, then it would make much more sense to me, if it were then "untranslated" by the same amount when given back to me. This would solve the problem and the Lingo code:

set the rect of window "sample" to the rect of window "sample"  

would maintain it's logical integrity across operating systems.

>From my knowledge, this has always worked this way. Or it has for a long time.

This may be true...
Then it's a bug that should have been fixed a long time ago... ;-)
Just my humble opinion... ;-)
Do with it what you wish... ;-) ;-)

-MikeS

The Rect of Window, Windows Bug

Top

Date: Jul. 7, 2000

In the process of tracking down a memory leak/fragmentation problem that surfaced in my Quipples project, I've created a new version of the DreamLight RAMLight. I was getting the NEW RAMLight 3.0 ready for release, with a quick test under Windows (since I develop on the Mac) when I noticed odd movement of the MIAW under Windows 98. Further investigation revealed a strange inconsistency.

I did a quick search on the net to see if there was any information about the problem but didn't turn anything up, so I figured I'd post a report to see if anyone else has seen this behavior and to have someone test it under D8 and other permutations of Windows. It's possible that there's something unique about my Win98 setup, since I would think this would have surfaced already if it were an across the board Windows problem.

DESCRIPTION:

Under Windows 98 setting the rect of a window and getting the rect of a window appear to be using different coordinate systems or offsets...

STEPS TO REPRODUCE:

  1. Open Director 7.0.2 under Mac OS 9.0.4
  2. Enter the following frame script in frame 1: on exitFrame set the rect of the stage to the rect of the stage go to the frame end exitFrame
  3. Run the movie. Nothing should happen since you are simply setting the rect of the stage equal to the rect of the stage which should be itself. Now for the fun part...
  4. Run the same movie under Director 7.0.2 under Windows 98.

In my case, what happens is the stage whizzes off the screen, step by step. It seems that getting the rect of the stage and setting the rect of the stage are using different coordinates or offsets for some strange reason and are not equal. So each time you set the rect to itself, it moves... This also happens with MIAW's using "the rect of window" and first surfaced in the RAMLight since it is a resizable MIAW it adjusts its own rect which works fine on the Mac but was causing it to move each time on Win98.

Has anyone else come across this behavior? Can someone try it under other permutations of Windows and also under D8 to see if they can reproduce it?

Thanks,
-MikeS

Strange Behavior, Recompile all Scripts!

Top

Date: Oct. 1, 1997

>I saw the above behavior just last night on two Macs running OS8 with 6.0

You probably already tried this but be sure to compile all scripts from the menu if strange things begin happening. Periodically I had run into some strange behavior of scripts no longer being recognized during calls to new( script "..." ) and it turned out that they simply need a recompile... ;-)

-MikeS

Initialize Rect of Sprite in BeginSprite
Before Using in BeginSprite

Top

Date: Sep. 22, 1997

Hi John,

The more I investigate this problem the stranger it gets... ;-)

After the information you posted and my last test I decided to go ahead and figure out just which properties could be used in a beginSprite handler.

So, I did the following;

  1. Create a rectangle sprite at (10,10,100,100) in sprite 1 frames 5-10
  2. Create a rectangle sprite at (20,20,200,200) in sprite 1 frames 15-20
  3. I set various random properties through the score such as moveable, blend etc...
  4. I created the following handler and attached it to both sprites
    on beginSprite me
      putProps me, "beginSprite"
    end
    
    on endSprite me
      putProps me, "endSprite"
    end
    
    on putProps me, fromHandler
      
      put ""
      put fromHandler && "Sprite Property Test"
      put "------------------------------------"
      
      set props to¬
     [ "backColor", "blend", "castLibNum", "constraint", "cursor", ¬
       "foreColor", "height", "ink", "left", "loc", "locH", "locV", ¬
       "memberNum", "moveableSprite", "puppet", "rect", "scriptNum", ¬
       "stretch", "type", "visible", "width" ]
      
      repeat with what in props
        do "put what & " & QUOTE & ":" & QUOTE & "&& the" && what && ¬
           "of sprite the spriteNum of me"
      end repeat
      
    end
    
  5. I then saved, opened and ran this and was astounded! This time the rect property was working 100% properly???
    -- ""
    -- "beginSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- "blend: 50"
    -- "castLibNum: 1"
    -- "constraint: 0"
    -- "cursor: 0"
    -- "foreColor: 116"
    -- "height: 90"
    -- "ink: 0"
    -- "left: 10"
    -- "loc: point(10, 10)"
    -- "locH: 10"
    -- "locV: 10"
    -- "memberNum: 4"
    -- "moveableSprite: 1"
    -- "puppet: 0"
    -- "rect: rect(10, 10, 100, 100)"
    -- "scriptNum: 2"
    -- "stretch: 1"
    -- "type: 16"
    -- "visible: 1"
    -- "width: 90"
    -- ""
    -- "endSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- "blend: 50"
    -- "castLibNum: 1"
    -- "constraint: 0"
    -- "cursor: 0"
    -- "foreColor: 116"
    -- "height: 90"
    -- "ink: 0"
    -- "left: 10"
    -- "loc: point(10, 10)"
    -- "locH: 10"
    -- "locV: 10"
    -- "memberNum: 4"
    -- "moveableSprite: 1"
    -- "puppet: 0"
    -- "rect: rect(10, 10, 100, 100)"
    -- "scriptNum: 2"
    -- "stretch: 1"
    -- "type: 16"
    -- "visible: 1"
    -- "width: 90"
    -- ""
    -- "beginSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- "blend: 50"
    -- "castLibNum: 1"
    -- "constraint: 0"
    -- "cursor: 0"
    -- "foreColor: 116"
    -- "height: 180"
    -- "ink: 0"
    -- "left: 20"
    -- "loc: point(20, 20)"
    -- "locH: 20"
    -- "locV: 20"
    -- "memberNum: 4"
    -- "moveableSprite: 1"
    -- "puppet: 0"
    -- "rect: rect(20, 20, 200, 200)"
    -- "scriptNum: 2"
    -- "stretch: 1"
    -- "type: 16"
    -- "visible: 1"
    -- "width: 180"
    -- ""
    -- "endSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- "blend: 50"
    -- "castLibNum: 1"
    -- "constraint: 0"
    -- "cursor: 0"
    -- "foreColor: 116"
    -- "height: 180"
    -- "ink: 0"
    -- "left: 20"
    -- "loc: point(20, 20)"
    -- "locH: 20"
    -- "locV: 20"
    -- "memberNum: 4"
    -- "moveableSprite: 1"
    -- "puppet: 0"
    -- "rect: rect(20, 20, 200, 200)"
    -- "scriptNum: 2"
    -- "stretch: 1"
    -- "type: 16"
    -- "visible: 1"
    -- "width: 180"
    
  6. So, I figured that something I was doing with the other properties was trigering an update of the rect property. To pinpoint exactly when the rect property was being calculated or updated I edited the behavior as follows:
    on beginSprite me
      putProps me, "beginSprite"
    end
    
    on endSprite me
      putProps me, "endSprite"
    end
    
    on putProps me, fromHandler
      
      put ""
      put fromHandler && "Sprite Property Test"
      put "------------------------------------"
      
      set props to¬
     [ "backColor", "blend", "castLibNum", "constraint", "cursor", ¬
       "foreColor", "height", "ink", "left", "loc", "locH", "locV", ¬
       "memberNum", "moveableSprite", "puppet", "rect", "scriptNum", ¬
       "stretch", "type", "visible", "width" ]
      
      repeat with what in props
        do "put what & " & QUOTE & ":" & QUOTE & "&& the" && what && ¬
           "of sprite the spriteNum of me"
        testRect me
      end repeat
      
    end
    
    on testRect me
      put the rect of sprite the spriteNum of me
    end
    
  7. I then saved, opened and ran this version and lo and behold, check this out...
    -- ""
    -- "beginSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- rect(0, 0, 0, 0)
    -- "blend: 50"
    -- rect(0, 0, 0, 0)
    -- "castLibNum: 1"
    -- rect(0, 0, 0, 0)
    -- "constraint: 0"
    -- rect(0, 0, 0, 0)
    -- "cursor: 0"
    -- rect(0, 0, 0, 0)
    -- "foreColor: 116"
    -- rect(0, 0, 0, 0)
    -- "height: 90"
    -- rect(0, 0, 0, 0)
    -- "ink: 0"
    -- rect(0, 0, 0, 0)
    -- "left: 10"
    -- rect(10, 10, 100, 100)
    -- "loc: point(10, 10)"
    -- rect(10, 10, 100, 100)
    -- "locH: 10"
    -- rect(10, 10, 100, 100)
    -- "locV: 10"
    -- rect(10, 10, 100, 100)
    -- "memberNum: 4"
    -- rect(10, 10, 100, 100)
    -- "moveableSprite: 1"
    -- rect(10, 10, 100, 100)
    -- "puppet: 0"
    -- rect(10, 10, 100, 100)
    -- "rect: rect(10, 10, 100, 100)"
    -- rect(10, 10, 100, 100)
    -- "scriptNum: 9"
    -- rect(10, 10, 100, 100)
    -- "stretch: 1"
    -- rect(10, 10, 100, 100)
    -- "type: 16"
    -- rect(10, 10, 100, 100)
    -- "visible: 1"
    -- rect(10, 10, 100, 100)
    -- "width: 90"
    -- rect(10, 10, 100, 100)
    -- ""
    -- "endSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- rect(10, 10, 100, 100)
    -- "blend: 50"
    -- rect(10, 10, 100, 100)
    -- "castLibNum: 1"
    -- rect(10, 10, 100, 100)
    -- "constraint: 0"
    -- rect(10, 10, 100, 100)
    -- "cursor: 0"
    -- rect(10, 10, 100, 100)
    -- "foreColor: 116"
    -- rect(10, 10, 100, 100)
    -- "height: 90"
    -- rect(10, 10, 100, 100)
    -- "ink: 0"
    -- rect(10, 10, 100, 100)
    -- "left: 10"
    -- rect(10, 10, 100, 100)
    -- "loc: point(10, 10)"
    -- rect(10, 10, 100, 100)
    -- "locH: 10"
    -- rect(10, 10, 100, 100)
    -- "locV: 10"
    -- rect(10, 10, 100, 100)
    -- "memberNum: 4"
    -- rect(10, 10, 100, 100)
    -- "moveableSprite: 1"
    -- rect(10, 10, 100, 100)
    -- "puppet: 0"
    -- rect(10, 10, 100, 100)
    -- "rect: rect(10, 10, 100, 100)"
    -- rect(10, 10, 100, 100)
    -- "scriptNum: 9"
    -- rect(10, 10, 100, 100)
    -- "stretch: 1"
    -- rect(10, 10, 100, 100)
    -- "type: 16"
    -- rect(10, 10, 100, 100)
    -- "visible: 1"
    -- rect(10, 10, 100, 100)
    -- "width: 90"
    -- rect(10, 10, 100, 100)
    -- ""
    -- "beginSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- rect(10, 10, 100, 100)
    -- "blend: 50"
    -- rect(10, 10, 100, 100)
    -- "castLibNum: 1"
    -- rect(10, 10, 100, 100)
    -- "constraint: 0"
    -- rect(10, 10, 100, 100)
    -- "cursor: 0"
    -- rect(10, 10, 100, 100)
    -- "foreColor: 116"
    -- rect(10, 10, 100, 100)
    -- "height: 180"
    -- rect(10, 10, 100, 100)
    -- "ink: 0"
    -- rect(10, 10, 100, 100)
    -- "left: 20"
    -- rect(20, 20, 200, 200)
    -- "loc: point(20, 20)"
    -- rect(20, 20, 200, 200)
    -- "locH: 20"
    -- rect(20, 20, 200, 200)
    -- "locV: 20"
    -- rect(20, 20, 200, 200)
    -- "memberNum: 4"
    -- rect(20, 20, 200, 200)
    -- "moveableSprite: 1"
    -- rect(20, 20, 200, 200)
    -- "puppet: 0"
    -- rect(20, 20, 200, 200)
    -- "rect: rect(20, 20, 200, 200)"
    -- rect(20, 20, 200, 200)
    -- "scriptNum: 9"
    -- rect(20, 20, 200, 200)
    -- "stretch: 1"
    -- rect(20, 20, 200, 200)
    -- "type: 16"
    -- rect(20, 20, 200, 200)
    -- "visible: 1"
    -- rect(20, 20, 200, 200)
    -- "width: 180"
    -- rect(20, 20, 200, 200)
    -- ""
    -- "endSprite Sprite Property Test"
    -- "------------------------------------"
    -- "backColor: 215"
    -- rect(20, 20, 200, 200)
    -- "blend: 50"
    -- rect(20, 20, 200, 200)
    -- "castLibNum: 1"
    -- rect(20, 20, 200, 200)
    -- "constraint: 0"
    -- rect(20, 20, 200, 200)
    -- "cursor: 0"
    -- rect(20, 20, 200, 200)
    -- "foreColor: 116"
    -- rect(20, 20, 200, 200)
    -- "height: 180"
    -- rect(20, 20, 200, 200)
    -- "ink: 0"
    -- rect(20, 20, 200, 200)
    -- "left: 20"
    -- rect(20, 20, 200, 200)
    -- "loc: point(20, 20)"
    -- rect(20, 20, 200, 200)
    -- "locH: 20"
    -- rect(20, 20, 200, 200)
    -- "locV: 20"
    -- rect(20, 20, 200, 200)
    -- "memberNum: 4"
    -- rect(20, 20, 200, 200)
    -- "moveableSprite: 1"
    -- rect(20, 20, 200, 200)
    -- "puppet: 0"
    -- rect(20, 20, 200, 200)
    -- "rect: rect(20, 20, 200, 200)"
    -- rect(20, 20, 200, 200)
    -- "scriptNum: 9"
    -- rect(20, 20, 200, 200)
    -- "stretch: 1"
    -- rect(20, 20, 200, 200)
    -- "type: 16"
    -- rect(20, 20, 200, 200)
    -- "visible: 1"
    -- rect(20, 20, 200, 200)
    -- "width: 180"
    -- rect(20, 20, 200, 200)
    

As soon as I made a call to "the left of sprite" the rect property was calculated, or updated or whatever and became available to the beginSprite handler.

So, an easy, albeit unintuitive, workaround to this problem is to access "the left of sprite" before accessing "the rect of sprite" in a beginSprite handler.

John, is there any way that lingo could be updated so that a call to "the rect of sprite" does whatever calculations are being triggered by a call to "the left of sprite" as well? This would seem to me to fix the problem. What do you think? Any other Macromedians have any other input about this problem?

Thanks,
-MikeS

Rect of Sprite in BeginSprite Shows Previous Sprite

Top

Date: Sep. 22, 1997

Hi John,

Thanks for the information. I went back and ran some more detailed tests based on your information.

The reason that the rect seemed to work within the beginSprite handler every time except the first was that it was using the "previous" rect. The first time through, there was no Previous rect so it reads rect(0,0,0,0). Once it loops or is replayed the rect seemed to be reading properly because there was only one sprite in the channel so the next time through it read the rect from the previous time through which happened to be the proper size because it was a prior instance of the same sprite.

  1. This shows up easiest by creating three different rectangle sprites in sprite channel 1.
  2. Use the score to set one to (10,10,100,100) the second to (20,20,200,200) and the third (30,30,300,300)
  3. Create the following behavior script
    on beginSprite me
      put ""
      put "BeginSprite Rect" && the rect of sprite the spriteNum of me
    end
    
    on midSprite me
      put "MidSprite Rect" && the rect of sprite the spriteNum of me
    end
    
    on endSprite me
      put "EndSprite Rect" && the rect of sprite the spriteNum of me
    end
    
  4. create the following frame script
    on exitFrame
      sendSprite( 1, #midSprite )
    end
    
  5. Attach the behavior to each of the three rectangles in sprite 1
  6. Attach the frame script to any frame in the middle of each of the three rectangles in sprite 1
  7. Save the movie, open and Run the movie and you'll get the following results:
    -- ""
    -- "BeginSprite Rect rect(0, 0, 0, 0)"
    -- "MidSprite Rect rect(10, 10, 100, 100)"
    -- "EndSprite Rect rect(10, 10, 100, 100)"
    -- ""
    -- "BeginSprite Rect rect(10, 10, 100, 100)"
    -- "MidSprite Rect rect(20, 20, 200, 200)"
    -- "EndSprite Rect rect(20, 20, 200, 200)"
    -- ""
    -- "BeginSprite Rect rect(20, 20, 200, 200)"
    -- "MidSprite Rect rect(30, 30, 300, 300)"
    -- "EndSprite Rect rect(30, 30, 300, 300)"
    

The beginSprite is reading the rect "before" it has been changed for the new sprite. This gives us the rect of the "previous" sprite instance. The midSprite and endSprite tests are correct.

This leads me to the following question. Is there any way that you guys could have a sprite's properties be initialized before the beginSprite is read? Also, can we get a list of which properties are and are not valid during a beginSprite?

Thanks,
-MikeS

SendSprite and the Invisible Me

Top

Date: Sep. 19, 1997

OVERVIEW:

When using the sendSprite command, an invisible "me" (or object reference) is created and passed along with the handler call. Normally this goes unnoticed as long as you create all your behavior handlers using the recommended "me" object reference.

If sendSprite doesn't find a handler in the target sprite object however, it passes through to scripts in the cast member, frame script and movie scripts. In these places it is not normal convention to use the me variable because normally these handlers are not associated with objects. Without a clear understanding of what's going on behind the scenes, this can cause trouble.

The Lingo Dictionary is incorrect on page 211 where it discusses the sendSprite command. As written the examples won't work, they are passing variables to the sendSprite command where they should be passing a symbol which is the name of a handler. The on-line entry for sendSprite however is correct, so refer to the on-line help rather than the printed lingo dictionary. ;-)

WHO AM I? EVEN AN OBJECT NEEDS AN IDENTITY:

A rather simple concept that can be difficult to grasp when beginning to write object oriented code is the use of the "me" variable. The term "me" is not a reserved word or any magical variable. It could be named anything such as "self" or "this", but "me" has become the convention in Lingo. It is simply a reference to an object in memory. It is primarily used to identify objects and to give an object a sense of its own identity.

Define an empty object by creating a parent script with nothing in it except a comment. Then name this script cast member "empty object":

-- "empty object" parent script

Then create (or "instance") a child object from this script like so:

-- in the message window type the following...
set childObj to new( script "empty object" )

put childObj 
-- <offspring "empty object" 2 aa25d5e>

What's put into the message window is a description of an object reference. This starts with the word "offspring" followed by the name of the cast member in the cast slot where the script was located when the object was first created. This is usually the name of the script itself unless you have moved cast items or loaded different casts after the object was created, in which case the name may not be correct. It is finally followed by hexadecimal numbers that represent the actual memory address where the object instance resides.

The way an object is identified is by this object reference.

When you typed: set childObj to new( script "empty object" )

Lingo gets the call to new( script "script name" ) and it creates an instance of the object defined in the script "script name". This instance is nothing more than an area of memory that contains a pointer to the script's compiled handlers (in this case nothing but a comment) and a copy of any property variables defined in the script (in this case none). To keep track of this new object instance, Lingo creates a reference to it which it returns to the calling statement. Now obviously this type of empty object is not of much use to anyone... ;-)

Let's take a look at a slightly more interesting object...

-- "simple object" parent script

property name

on new me, whatName
  set the name of me to whatName
  return me
end

on getName me
  return the name of me
end

And let's instance a child object from this new script the same way we did previously but this time add a name after the script as so:

set childObj to new( script "simple object", "Fred" )

childObj 
-- <offspring "simple object" 2 aa25f0c>

Doesn't look much different, but after Lingo created the object reference this time, it then looked into the object script itself to see if it contained its own "new" handler and it found one. So it passed the object reference <offspring "simple object" 2 aa25f0c> and the string "Fred" off to this handler which interpreted it in this way.

on new <offspring "simple object" 2 aa25f0c>, "Fred"
  
  set the name of <offspring "simple object" 2 aa25f0c> to "Fred"
  
  return <offspring "simple object" 2 aa25f0c>
end

(NOTE: <offspring "simple object" 2 aa25f0c> is a description of the object reference only, it can't actually be typed out this way in a real Lingo statement it is only shown in these examples for explanation. This is the description of the reference that would be passed to the "me" variable)

So within the scripts "new" handler, the handler can refer to the property variable that belongs to this particular object in memory since it has a reference to the object itself. This way the object has a sense of "self" through the "me" variable.

When the new handler reaches the return statement, it returns the value of me <offspring "simple object" 2 aa25f0c> back to the original calling statement. Then this returned object reference <offspring "simple object" 2 aa25f0c> is bound to the variable named "childObj".

To find the name of the child object, simply ask it this way:

put getName( childObj )

This passes the object reference stored in "childObj" to the getName handler in the object's parent script like so:

on getName <offspring "simple object" 2 aa25f0c>
  
  return the name of <offspring "simple object" 2 aa25f0c>
  
end

Or, you could simply access the name property variable directly, the same way the handler does by typing this:

put the name of childObj

--Which becomes:
put the name of <offspring "simple object" 2 aa25f0c>

So the me variable is used as a way to identify which particular object you are talking about and to let the handlers themselves know which object instance to work on. This is how one parent script can work on any number of instanced child objects, through these references.

BEHAVIORS:

Behaviors are really not something entirely new as you might expect. They are nothing more than a simplified way to use parent/child objects. When a sprite begins, Lingo automatically creates a child instance of the behavior script just as it would for a parent script. It automatically puppets the sprite, creates a property variable for the object called "spriteNum" and initializes it to the number of the sprite channel. This new instance is then stored in an internal list of sprites.

The behavior handlers can keep track of the current object through use of their own "me" variable.

Technically, if a particular handler of a behavior (or parent script) does not need to access items in the object instance itself through the me variable and has no other arguments, you could leave off the "me" variable. This can lead to problems however because the object reference is usually passed to the handler anyway as the first parameter. This means that if you want to add arguments to the handler, you need to skip the first argument which would be passed the object reference. The easiest way to do this is to always use the "me" variable as the first argument of any behavior or parent handler you are creating.

PROPER USE:

Let's say we have a behavior with a handler named "handleSomething" accepting an argument called "anArgument". Since it is part of a behavior which is really nothing more than a simplified parent/child object, it would normally be written with the me variable as such:

-- SomeBehavior

on handleSomething me, anArgument
  put "Now I'm doing my thing with anArgument:" && anArgument
end

Create a rectangle in sprite 1 from frames 1 to 20. In frame 20 put a "go to the frame" loop.

on exitFrame
   go to the frame
end

Attach the behavior to sprite 1 and run the movie. While it's running enter this into the message window.

sendSprite( 1, #handleSomething, "TEST" )
-- "Now I'm doing my thing with anArgument: TEST"

To verify that this behavior is indeed an object enter the following:

put the scriptInstanceList of sprite 1
-- [<offspring "Something Behavior" 1 aa258e0>]

--Now when you typed in:
sendSprite( 1, #handleSomething, "TEST" )

Lingo looks up the object reference for any behaviors attached to sprite 1 and finds: <offspring "SomeBehavior" 1 aa258e0>

It then creates the following type of call:

handleSomething( <offspring "SomeBehavior" 1 aa258e0>, "TEST" )

It's very important to note here that the first argument passed is not "TEST" as you might have thought but rather the object reference. This object reference is then caught by the "me" variable as we saw with normal child objects as follows:

on handleSomething <offspring "SomeBehavior" 1 aa258e0>, "TEST"
  put "Now I'm doing my thing with anArgument:" && "TEST"
end

So you can see that even though the me <offspring "SomeBehavior" 1 aa258e0> is not used anywhere inside the handler, it is still passed as the first argument and must be caught.

Now comes the tricky part. Normally if we were writing a handler in a movie script, we wouldn't use the me variable since the handler is not used with any object and an object reference is not passed. However, if the sendSprite command does not find an appropriate handler in the target sprite, it looks through the cast, frame and movie scripts for a matching handler. If it finds a match, it executes it and passes it the same arguments it would have passed the target object, including the target's object reference.

The following handler in a movie script may seem to be written properly since it's not an object:

on handleSomething anArgument
  put "Now I'm doing my thing with anArgument:" && anArgument
end

However, if this is called as the result of a sendSprite, the "anArgument" variable will not receive the argument you might have expected, but rather a reference to the target object!

Therefore, if you are writing a handler that is to catch a message from a sendSprite call you must deal with the object reference as well. The handler should be rewritten like this:

on handleSomething originalTargetObject, anArgument
  put "Now I'm doing my thing with anArgument:" && anArgument
end

Notice that I've added a new first argument to catch the object reference but I did not use the traditional "me" variable. In this case, using the "me" variable could be confusing because the value passed would not really be a reference to this script's object. Since the handler is in a movie script, there is no object. The value passed is a reference to the original target object. You could name this variable anything you want, originalTargetObject seemed appropriate.

Now go forth and communicate with many sprites using sendSprite... ;-)

-MikeS

Rect of Sprite in BeginSprite Bug

Top

Date: Sep. 18, 1997

DESCRIPTION:

The rect of sprite does not work properly within a beginSprite handler the first time a movie is run. (Actually it doesn't work at all, see later notes above...)

STEPS TO REPRODUCE:

  1. Create a new movie
  2. In Frame 10, Sprite 1, create a rectangle cast member on stage
  3. Open the script editor
  4. Enter the following script...
    on beginSprite me
       put the rect of sprite the spriteNum of me
    end
    
  5. Set the script type to score script
  6. Drag this new score script to the sprite you created in frame 10/sprite 1
  7. Run the movie...

    Seems fine. In frame 10 the rectangle appears and the message window reports the rect properly. Now comes the fun part... ;-)

  8. Save the movie
  9. Reopen the movie from the saved file
  10. Immediately run the movie without touching anything else...

You will be told the rectangle is rect(0, 0, 0, 0) the first time it runs. If you subsequently play it again while it's open it works fine but the very first time it's run the rect function does not work properly within the beginSprite...

ENVIRONMENT:

Tested in D6.0 on a Macintosh 9500 MaxPower MP400+ 240MB RAM running MacOS 7.6.1

Can anyone else verify this for me?

:-)

-MikeS

Breaking Behavior References in the Score

Top

Date: Sep. 5, 1997

>One option would be to try to
>maintain referential integrity, so that when the castmember is deleted, the
>reference to it by the score is also deleted.

If I had a frame script in the score and I delete the script from the cast, I would like the score reference to be deleted as well. This is by far the most intuitive approach I can think of. Going the other way, leaving the reference to a blank cast slot is fraught with dangers that I don't think are justified. I had run into this myself and reported it as a bug since it is far from intuitive behavior.

If someone pastes a new script over an older script in the cast, then the score references could be maintained to point to the new script.

> The problem is that this
> would break authoring techniques.

I don't use any authoring techniques that use this "feature", though others out there may. If so I think using this "feature" came about from exploiting an obscure situation. I think that streamlining the product and tightening its intuitiveness would be a better solution than trying to save obscure authoring techniques. If many people out there are using this "feature" during authoring then perhaps you could create a user preference that they could turn on. But for the majority of users it would be safer to default this new preference to maintaining referential integrity.

--

Here are some comments I had as I wrestled with this topic upon first using D6... If I found this confusing, just imagine how a poor newbie would feel... Maybe these comments will spark some ideas on how to make this more intuitive.

How many of you out there have accidently opened a script window which then creates a blank "on exitframe" script and enters it into the score?? I'll bet everyone out there. Here's an idea. If one of the script windows is called up which creates a blank "on exitframe" script, if it is then closed without being edited in any way simply make it disappear into oblivion. I can't tell you how many times I've given a file to a beginner to edit castmembers, and when I get it back, there are all types of blank scripts attached to everything known to man because they accidently opened those windows and didn't know how to "cancel" out of them by fully deleting all the text in the window (which isn't very intuitive) Any votes for that change?? At the very least let's just put a real "Cancel" button on the script window which would close it without entering changes and would delete a script that the user never edits in the first place.

It appears that there are a few bugs with the script channel, I'm getting some very erratic behavior... It almost looks like Director 6 is trying to do just what I outlined above but not entirely successfully. Here's what happens...

1) I open a brand new file.

2) I double click on the script channel in frame 1. This opens the expected Score Script 1 window with the empty "on exitFrame" handler...

3) I realize I don't want a script so I immediately close the script window without editing anything. This now creates a behavior icon in cast member #1 but the castmember itself appears empty and enters the #1 in the score script channel.

4) I then double click on cast memeber #1 and it opens the new behavior inspector. So far, I'm not sold on having this open rather than the script itself but I'll suspend my judgement until I'm more used to the new behaviors. It's great to see that you've supplied a preference for this just in case.

5) I then click the little script icon on the behavior inspector and it opens a completely blank script, no "on exitframe"...

6) I then close that window and boom, the cast member 1 behavior icon is gone and cast member 1 is empty. However there is still an entry in the script channel in frame 1 and it refrences the now empty cast member #1???

7) I click on cast member #1 and nothing happens, it's gone. But it's still entered as a 1 in a little blue box in the script channel of frame 1.

8) So, I then switch to the score window and get another surprise. This time the #1 disappears from the script channel of frame 1 but the blue box remains there...

9) I now double click on the script channel of frame #10. This opens the expected Score Script window with the blank "on exitframe" script ready for me. But here's another surprise. If I look at the score the 1 is now entered in frame 10 AND it's back in frame 1 again...

10) I close the script window (without editing anything again) and I get the blank cast member with behavior icon in cast member #1 again.

11) I now go to the score and double click on the frame 20 script channel. This opens a new Score Script 2 window with an empty "on exitframe" handler as expected.

12) This time I add a comment between the on and end like this...

on exitFrame
	--boo
end

13) I then close the window. Now cast member #2 shows the beginning of the script starting with on exitFrame and it has the behavior icon, so when I edit the script it seems to handle everything ok but when I close the script editor window without adding to the script it seems to "half delete" the script castmemeber...

So right now I have cast member 2 looking correct but cast member 1 is blank except for the behavior icon. My script channel has a 1 in frames 1 and 10 and a 2 in frame 20...

14) I now go back to the score and double click on the 1 in frame 10's script channel. This opens a completely empty Score Script 1 window...

15) I then close that window without editing anything. Surprise, the castmember behavior icon disappears from cast member 1 and the 1's dissapear from the script channel in the score, however, the blue boxes remain there...

Here's another one for you.

1) Double click a script channel frame. It opens the Score Script Editor for cast member #1 as before.

2) Imediately close it without editing. You get a 1 in the script cell you clicked in and the blank behavior iconized in cast member #1

3) Now immediately Undo. Surprise. It undoes the entry in the score but leaves the blank behavior iconized script cast member in your cast. You can keep doing this and fill your cast up with blank behaviors that then disappear if their script windows are opened and closed.

-MikeS

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