Articles Archive
Articles Search
Director Wiki
 

The Name of the Sprite

September 21, 2001
by Darrel Plant

The issue of naming sprites comes up regularly in discussions of how Director could be improved. Developers coming from Flash wonder why they should have to refer to objects on the Stage by some abstract number rather than a functional identifier. Defensive old-timers say that it isn't all that hard, ferpetessake, while often working up their own techniques for sprite identification.

Rob Romanek wrote an article on the subject last spring ("Movie variables and sprite.name"), but in true Director tradition, there's more than one way to get the job done, so here's another option.

KISS

Most of the inquiries I've had from people about a sprite naming system have come, naturally, from developers who weren't writing behavior dialogs. They were doing Lingo programming -- otherwise there wouldn't be a need to refer to sprites at all -- but not necessarily complex programming, so I wanted to develop a system that was as simple as possible to implement and understand. It doesn't have all the bells and whistles that Rob's version does, but for many purposes it works just fine.

My simple sprite naming system begins with a behavior (Sprite Namer). that displays a dialog box when it's dragged onto a sprite.

This is all pretty simple. The property set in the dialog box -- pName -- is a string. A symbol would be more efficient for memory storage and lookups, but for ease of use, I've used a string.

Just like other Director sprite naming systems, the beginSprite and endSprite handlers are used to register the sprite's name (as set in the dialog) and channel (derived from me.spriteNum).

The getPropertyDescriptionList handler for this behavior is about as simple as it can be. The default name used when the behavior is first dragged onto a sprite is a combination of the word sprite and the sprite channel number. You don't need to do anything with this behavior.

property pName

on beginSprite me

  spriteList (#add, pName, me.spriteNum)

end


on endSprite me

  spriteList (#rem, pName, me.spriteNum)

end


on getPropertyDescriptionList

  vName = "sprite" & the currentSpriteNum
  return [#pName: [#comment: "Sprite Name", #format: #string, #default: vName]]

end

WWDD?

That's the behavior portion of this system. Pretty simple so far, eh? This is the entire rest of the system:

global gSpriteList

on prepareMovie

  gSpriteList = [:]
  gSpriteList.sort ()

end


on spriteList op, sName, sChan

  case op of
    #add:
      if not voidP (gSpriteList[sName]) then
        alert "sprite name" && sName && "already exists"
      else
        if gSpriteList.getPos (sChan) then
          alert "sprite channel" && sChan && "already allocated"
        else
          gSpriteList.setaProp (sName, sChan)
        end if
      end if
    #rem:
      if voidP (gSpriteList[sName]) then
        alert "sprite name" && sName && "does not exist"
      else
        gSpriteList.deleteProp (sName)
      end if
  end case

end


on nSprite sName

  return sprite (gSpriteList[sName])

end

This is a movie script, and it just needs to appear in the movie once.

The global variable gSpriteList is a property list that keeps track of the sprite names and associated channel numbers. It needs to be initialized in the prepareMovie handler in order to be ready when sprite behaviors are initialized for anything in frame 1.

The spriteList handler is used to both add and delete sprites from the gSpriteList variable. The op parameter tells the handler whether the sprite is being added to the list (during a beginSprite event) or removed from the list (during an endSprite event).

The most important of the three alerts clues you in to whether you've got two co-existing sprites that have the same name. The other alerts are there only for completeness, because there isn't any way two sprites can exist in the same channel, and they shouldn't be removed from gSpriteList before the endSprite event except in the case of an error.

When a sprite with the Sprite Namer behavior attached to it is instanciated, the name specified in the behavior is added to gSpriteList as a property, with the sprite channel as its value. If a sprite in channel 1 is named ball, and it's the first sprite with the behavior attached, gSpriteList will be equal to:

  ["ball": 1]

If sprite 2 contains a sprite named box, once its behavior registers its name, gSpriteList will look like:

  ["ball": 1. "box": 2]

WYSIWYG

The last handler in the movie script is what you use to reference a named sprite. When you feed it a sprite name as a string, it looks up the name in gSpriteList and returns a reference to the sprite object, not merely the sprite channel number. (This is similar to other approaches to sprite naming.) So, in the example above, instead of referring to the box sprite in this manner:

  sprite (2).loc = point (40, 50)

you can use the nSprite function to refer to the sprite's name as set in the Sprite Namer behavior dialog:

  nSprite ("box").loc = point (40, 50)

Unlike some sprite naming routines, this one doesn't broadcast messages using sendAllSprites, so you don't need to worry about messages going all over the place.

Just how fast is the lookup routine? Won't it slow down the movie if you have to look up a bunch of values from a property list where the properties are strings? The answer is yes, to some extent. I've included two test routines in the code for the sample movie called lookupteststr and lookuptestsym, which both create a property list of 1000 property/value pairs with strings and symbols, respectively, as the property values. They then create a random list of 100 property names to look up. Finally, they time a test of 1000 lookups by going through the lookup list 10 times. On a Mac G4/400, the test with string values as property names averages about 30 milliseconds for 1000 lookups; for symbols it's about 25ms. With only 10 items (representing 10 named sprites) in the property list, 1000 lookups takes about 15ms for strings and 10ms for symbols. It's not blindingly fast, in other words, but it should be adequate if you don't need to name all of your sprites. (These tests can also prove the value of sorting your lists; commenting out the sort command in lookupteststr made it 50 times slower when the property list had 1000 items in it.)

So there's yet another approach to named sprites. What do you need to do to implement it?

  1. Copy the Sprite Namer behavior to your cast and use it to name each sprite you want to be able to refer to by name.

  2. In the movie script (and in every script where you want to refer to sprites by name), define the global variable gSpriteList.

  3. Initialize and sort the gSpriteList variable in the movie's prepareMovie handler (along with any other operations you may want to perform there).

  4. Add the spriteList and nSprite handlers to a movie script.

  5. Use the nSprite function to refer to sprites by the names you assigned to them in the Sprite Namer behavior.

What's the main pitfall of this technique? Strings used as property names are one of the few areas where Director is case-sensitive, so you need to make sure that every time you reference a sprite name that you match the case in all characters. Personally, I prefer to use symbols instead of strings for sprite names, but strings allow you to use spaces and other non alphanumeric characters.

In the movie below, the field at the lower left displays the contents of gSpriteList. As the sprites appear and disappear, you can see their references get added and removed from the list.

A Director 7-compatible version of this movie is available for download for Mac and Windows.

Darrel Plant is Technical Editor of Director Online. He is the Publisher at Moshofsky/Plant Creative Services in Portland, Oregon, and the author of or contributor to a number of books on Macromedia Director and Flash, including Special Edition Using Flash 5,, Flash 5 Bible, and Director 8.5 Studio..

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