[14.7] I want to put objects on the stage on the fly. How do I allocate channels?

The key thing to realize is that the objects you create, and the sprites onstage, are separate entities. The sprites will behave just like sprites always behave, whether you're controlling them with objects or ordinary lingo scripts.

In order to put an object onstage, you have to have a channel for it to go into, and in order to use that channel, it must already have something in it. So, if you want to create a bunch of object-sprites, you need to prepare the channels for them in advance when you create the movie.

Decide on a range of channels that you'll set aside to put the objects in when you create them. Put some dummy sprites into these channels: an invisible tools palette rectangle is good for this, since it doesn't take up much space (use the same cast for all these dummy sprites rather than having one each!). You may want to start the movie with all these sprites safely offstage where they won't get in the way.

The sprites you choose needn't be contiguous, but it's probably easier to keep track when you set it up if they are.

Make a list of all the channels that are available for objects to use, and put it in a global variable at the start of your movie, eg:

    global freeChannels
    
    on startMovie
      put [5,6,7,8,9,10,11,12] into freeChannels
      -- and whatever other stuff you want
    end startMovie

Since you're going to manipulate these channels using lingo (in this case child objects), you'll need to make them puppets. It doesn't matter where you do this as long as it's *before* you start using them. A convenient place might be your startMovie handler, but anywhere will do :

    repeat with pup in freeChannels
      puppetSprite pup, true
    end repeat
You've now got a list of channels that are all puppeted and ready to use. There are a number of ways in which you can allocate channels from this list, but I'll just suggest one possibility:
    -- in your parent script
    
    property myChannel
    global freeChannels
    
    on birth me
      -- check that there's a channel available
      if count(freeChannels) = 0 then return #cantAllocate
      -- otherwise, take the first channel and use it
      set myChannel = getAt(freeChannels, 1)
      -- remove it from the free list, so no-one else uses it
      deleteAt freeChannels, 1
      -- do whatever else you want
      -- and finish
      return me
    end birth
There's a couple of things to notice about this. One is that the handler returns an error code if it can't allocate a channel. Whenever you birth an object from this script, you'll need to check what you get back to make sure it's worked OK. In more complex scripts, there might be several ways the birthing could, er, miscarry, and you might want to return different error codes so that you'll know what went wrong and can deal with it appropriately.

The other thing is that each time an object gets birthed, freeChannels gets smaller, until there's nothing left. Once the list is empty, that's it: when you run out of channels, you can't create any more.

But let's say the sprites in question don't only get created, they also get destroyed -- maybe they're little space invaders or something. You need to be able to reclaim the channels once they're no longer in use, so that you can use them again (on the next level, with the bigger, meaner and more bloodthirsty invaders...).

You might just have a total reset handler that you call each time you start afresh:

    on startNewLevel
      put [5,6,7,8,9,10,11,12] into freeChannels
    end startNewLevel
but this may be too restrictive. If you want to be able to create and destroy sprites on the fly, you'll need to have the object give back the channel it's using once it's finished with it. This ability becomes one of the object's own handlers (in the parent script) :
    on die me
      doHugeExplosion(myChannel)
      add freeChannels, myChannel
      set score = score + 100
    end die
Or whatever. These examples are pretty banal, but you get the idea.