Articles Archive
Articles Search
Director Wiki
 

Automating Your Authoring Some More

March 29, 2002
by Danny Kodicek

A while ago, I wrote two articles ("Automating Your Authoring", Part 1 and Part 2) about author-time scripts, which looked at some ways that you can speed up repetitive processes during production. Since then, I've had occasion to use a few more techniques along these lines, and I thought it might be useful to extend the article to take in two of these methods. Some of these might seem a little more obscure, so I've given some examples of how they might help you in practice. If you are new to authoring scripting techniques, I recommend that you take a look at the previous articles before tackling this one.

Organising Your Score

The first set of methods I've evolved involve ways to work with your Score. Generally I tend to work mostly in one frame "chunks", so these techniques are designed with that in mind, but they can be adapted to more animation-based approaches, too.

Here's the problem: suppose you are working with a large number of alternating sprites (for example, a number of buttons, each of which has a text sprite above it as a label). In Director, it's no small task to make a change to all of these at once - for example, to move them all one place to the left, or to change a behaviour property. You have to select all of them, and doing this in the Score means you have to click each one individually, while doing it on the Stage is also impossible if the alternate sprites sit on top of the ones you want to change.

So here are a number of methods for dealing with this kind of problem. All of them take advantage of the fact that we can give sprites a particular colour in the score, which is accessible by the scoreColor property.

Assuming you have just decided to use this approach, the first task is to colorise the particular sprites you are interested in. Of course, in some cases the only way is to do this step by hand, but often you will find that there is some common element to the sprites which you can exploit. For example, they may all be instances of a particular cast member, or they may all be of a particular type, such as bitmaps. Let's write a script which allows both these possibilities:

on selecttype t, n

  -- t is either a string or integer, representing the name or number of
  -- the member to be selected, or a symbol representing a type such as #bitmap
  -- n = 1 to select sprites in the whole score,
  -- n = 2 to select sprites over the currently selected range
  -- n = 0 or void to select the current frame
  s=[]
  if n=1 then
    rg=[[1,the lastchannel,1,the lastframe]]
  else if n=2 then
    rg=the scoreselection
  else
    rg=[[1,the lastchannel,the frame, the frame]]
  end if
  b=the frame
  repeat with l in rg
    repeat with f=l[3] to l[4]
      go f
      repeat with i=l[1] to l[2]
        if stringp(t) then
          if sprite(i).member.name=t then s.add([i,i,f,f])
          
        else if integerp(t) then
          if sprite(i).member.membernum=t then s.add([i,i,f,f])
          
        else if symbolp(t) then
          if sprite(i).member.type=t then s.add([i,i,f,f])
        end if
        
      end repeat
    end repeat
  end repeat
  go b
  the scoreselection=s

end

Try it. You should be able to use it to select groups of sprites in any range of frames, of particular member names or types.

Be aware that you may not get the results you want if you use this method to select parts of sprites that are stretched over several frames. As I mentioned, I use this method for one-frame sprites. For simplicity, I'll make all the following handlers ignore the possibility that you may want to select over more than one frame - the technique remains the same as here, though.

I've left the above handler on its own because it's useful in its own right, but now we want to use it to colorise the sprites we're interested in.

on colorise t, n

  selecttype (t)
  repeat with s in the scoreselection
    repeat with i = s[1] to s[2]
      sprite (i).scorecolor = n
    end repeat
  end repeat

end

Once that's done, it's a simple matter (essentially the same technique as we used before) to select all the sprites of a particular scoreColor on the current frame:

on selectcolour c

  if voidp (c) then c = the scoreselection[1][1].scorecolor
  s = []
  repeat with i = 1 to the lastchannel
    if sprite (i).scorecolor=c then s.add ([i,i, the frame, the frame])
  end repeat
  the scoreselection=s

end

These methods may seem a little obscure, but trust me -- on a complex movie, they can save you a lot of time. Combined with the next set of techniques, they can be even more effective.

Working With the scriptList

The Property Inspector has saved us a lot of work with behaviours - I'm sure many people remember with the same horror as I do the effort involved in changing the value of a single property over 100 sprites. Thankfully, that is now past - we can select all the sprites, choose the behaviour tab, and just enter the new value. But suppose we want to do something a little more complex? Using the scriptList property we can do some pretty wacky things. Let's look at this property in more detail.

Here's a sample behaviour script which you can place on a sprite:

property p1, p2, p3, p4

on getpropertydescriptionlist me

  l = [:]
  l[#p1] = [#comment:"Prop1", #default: 1, #format: #integer]
  l[#p2] = [#comment: "Prop2", #default: "", #format: #string]
  l[#p3] = [#comment: "Prop3", #default: 1, #format: #integer, #range: [#min: 0,#max: 10]]
  l[#p4] = [#comment: "Prop4", #default: #choice1, #format: #symbol, #range: [#choice1, #choice2, #choice3]]
  return l

end

It doesn't do a lot, but if you drag it to a sprite it'll allow you to set the values of these four properties. Now try this in the message window (I assume you've put the script on a sprite in channel 1)

put sprite (1).scriptlist
-- [[(member 3 of castLib 1), "[#p1: 1, #p2: "", #p3: 1, #p4: #choice1]"]]

What is this showing you? Well, it's a list of lists, as you can see, one for each behaviour on the sprite. Each of the inner lists (just one in this case) is two elements long, consisting of a script cast member reference and a string of the list of elements of the getPropertyDescriptionList handler. I don't know why this is returned as a string, but I'm sure there's a good reason.

Now let's have some fun with this. The most common reason I've found for using the scriptList is when I want to number various behaviours sequentially. So here's a somewhat complex script which deals with this possibility. You can hand it a script name or number, and a property list with additional optional parameters: a property name (symbol), number in the getPropertyDescriptionList, or a string with the comment property (this is what displays in the Property Inspector, so it's often the easiest thing to remember), a base string (for properties named index1, index2, etc, you can give it "index"), a start and/or stop number, an option for dealing with parameters with min or max values (either start again from the bottom or keep all remaining values at the end value), a step value and an ascending or descending parameter. The handler always traverses the sprite channels in the order they appear in the scoreSelection.

The whole script is in the accompanying movie, since it includes a lot of code which is just intended to deal with the various possibilities of the property list, and a lot of error checking (not at all complete, even now - but of course, one of the great advantages of authoring scripts is that you don't need to worry so much about error checking - you wrote the script, after all, so you should know what parameters you can send it. So all I'm including here is the main part, walking through the scripts.

on sequenceparams par, scr
  -- a whole lot of error checking here
  if par.descending then ind=par.maxnum
  else ind=par.minnum
  covered = []
  repeat with s in the scoreselection
    if the frame < s[3] or the frame > s[4] then next repeat
    repeat with i = s[1] to s[2]
      if covered.getone(i) then next repeat
      covered.add(i)
      sc = sprite(i).scriptlist
      repeat with j = 1 to sc.count
        l = SC[j]
        if l[1] = scr then exit repeat
      end repeat
      if j > sc.count then next repeat

      v = value(l[2])
      if typ = #string then v[par.prop] = par.basestring&ind
      else if rng = #none then v[par.prop] = ind
      else if ilk (rng,#linearlist) then v[par.prop] = rng[ind]
      else v[par.prop] = ind
      l[2] = string(v)
      sprite (i).setScriptList (SC)
      if par.descending then
        ind = ind - par.step
        if par.minnum <> #inf then
          if ind < par.minnum then
            case par.atbottom of
              #stay: ind = par.minnum
              #restart: ind = par.maxnum
              #otherend: ind = rng.max
            end case
          end if
        end if
      else
        ind=ind + par.step
        if par.maxnum <> #inf then
          if ind > par.maxnum then
            case par.attop of
              #stay: ind = par.maxnum
              #restart: ind = par.minnum
              #otherend: ind = rng.min
            end case
          end if
        end if
      end if
    end repeat
  end repeat
end

As you can see, even without the error checking code, this is still quite a long script. But that is because it's aiming to be very versatile, covering a lot of possible uses. The essence of the code is contained in these lines:

v=value(l[2])
if typ = #string then v[par.prop]=par.basestring & ind
else if rng = #none then v[par.prop]=ind
else if ilk(rng, #linearlist) then v[par.prop] = rng[ind]
else v[par.prop]=ind
l[2] = string(v)
sprite (i).setScriptList (SC)

Note the setScriptList command. You can't set the scriptList directly, you have to use the setScriptList function. Have a play with it -- use the behaviour I used before.

Try typing things like this in the Message window of the source movie (don't forget to select all the sprites you're interested in first - don't worry about selecting anything that doesn't have the script in question, it'll be skipped)

sequenceparams
sequenceparams [#prop:"prop2",#basestring:"index",#minnum:3]
sequenceparams [#prop:#p3,#maxnum:3,#atbottom:#otherend,#descending:1]
sequenceparams [#prop:#p4,#attop:#restart]

Well, I'll stop here. I hope these ideas have been useful -- or at least the scripts themselves! It really is worth using techniques like this in a complex project -- they can save you many boring hours. And writing the scripts themselves can be quite fun, too.

A sample Director 8.5 movie is available in SIT or ZIP archives The demo includes some sample casts and a PHP script file. The demo movie checks a folder on my personal server for new files.

All colorized Lingo code samples have been processed by Dave Mennenoh's brilliant HTMLingo Xtra, available from his site at http://www.crackconspiracy.com/~davem/

Danny is a mathematician by training, an occasional writer, actor and, for the last four years, programmer. He is self-taught in Director and it occasionally shows. He is part of the company Wellspring Interactive Ltd and has just finished working as Head of Clues on their first major project, TimeHunt.

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