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.