Invadir 16 - Getting connected
| In earlier versions of this tutorial, this lesson discussed the score and the concept of states. Now, that content has been moved into the next lesson. Apologies for any confusion. |
Now that we have a 'connector' sprite broadcasting a message to all the other sprites, it's time to use that message and, more importantly, the parameter that comes with it to set up all the sprites with their appropriate shared property values.
The bullet, invader, cannon and scorer scripts will all now need a handler like this:
on storeShared me, gameSprites set invaders to the invaders of gameSprites set bullets to the bullets of gameSprites set cannon to the cannon of gameSprites set scorer to the scorer of gameSprites end
The value arriving as the parameter gameSprites is a pointer to a property list in memory. All the sprites receive the same pointer, so all the sprites share this data. The cannon and scorer data are more simple, low-level datatypes called integers (whole numbers). These are not passed by reference, but it doesn't matter, it is only the multiple objects (bullets and invaders) which need to be handled in this way. It is, after all, the bullets and the invaders which are going to be shooting and dying in varying quantities.
All assignment statements relating to these properties in the beginsprite handler of these scripts are overridden. You may remove them if you wish.
Now because lists are passed 'by reference', each object stores a reference to the same list of bullets and invaders. This means that each bullet can remove itself from the bullet list when it starts shooting, then add itself when it is finished. Each sprite stores a reference to the same list so they can all 'see' immediately which bullets are available.
Here is how the bulletscript would look with this added.:
-- BULLET SCRIPT --
property mySprite -- sprite channel
property shooting -- Boolean (either True or False)
property invaders -- list of invader sprite channels
property vdirection -- either 1 or -1
property speed -- pixels per frame
property shootsound -- sound cast member name
property cannon -- sprite channel
property soundChan -- sound channel
property offstage -- large negative value
property bullets -- list of bullet sprite channels
on beginsprite me
set mySprite to the spritenum of me
set shooting to false
set shootsound to "blast"
set speed to 8
set vdirection to -1
set soundChan to 2
set offstage to -999
-- note, some lines have been removed from this handler --
-- you do not have to remove them, but you can if you wish --
-- here are the lines which have been removed: --
-- set invaders to [3, 4, 5, 6, 7, 8, 9, 10]
-- set cannon to 1
end
on storeShared me, gameSprites
set invaders to the invaders of gameSprites
set bullets to the bullets of gameSprites
set cannon to the cannon of gameSprites
set scorer to the scorer of gameSprites
end
on exitFrame me
if not shooting then
return
end if
set myV to the locV of sprite mySprite
if myV < 0 or myv > the height of the rect of the stage then
set shooting to false
set the locV of sprite mysprite to offstage
add bullets, mysprite -- ready again, so adds itself to shared list
return
end if
if vdirection = 1 then
set possibleTargets to [cannon]
else
set possibleTargets to invaders
end if
repeat with target in possibleTargets
if sprite mysprite intersects target then
hit sprite target
if target = cannon then
-- End of life
else
deleteOne invaders, target -- removes invader from shared list
if invaders = [] then
-- End of level
end if
end if
set shooting to false
add bullets, mysprite -- ready again, so adds itself to list
set the locV of sprite mysprite to offstage
return
end if
end repeat
set the locV of sprite mySprite to myV + (vdirection * speed)
end
on shoot me, whosShooting
if shooting then
return
end if
set shooting to true
deleteOne bullets, mysprite -- busy, so removes itself from list
set the loc of sprite mysprite to the loc of sprite whosShooting
if whosShooting = cannon then
set vdirection to -1 -- shooting upwards
else
set vdirection to 1 -- shooting downwards
end if
puppetsound soundChan, shootsound
end
Remember that the invader and cannon script will also need the storeShared handler. Here it is again:
on storeShared me, gameSprites set invaders to the invaders of gameSprites set bullets to the bullets of gameSprites set cannon to the cannon of gameSprites set scorer to the scorer of gameSprites end
Add it now. You should also ensure that each of these scripts includes declarations of the following properties:
property invaders -- list of invader sprite channels property bullets -- list of bullet sprite channels property cannon -- sprite channel property scorer -- score sprite channel
For the actual shooting in the invader and cannon script, things will look like this:
Add these lines to the cannon script
if the shiftdown then
if bullets = [] then
return -- no bullets are available right now so leave handler
end if
set bullet to getAt(bullets,1) -- first available bullet in list
shoot sprite bullet, mysprite -- sends own sprite channel as extra parameter
return -- leave handler
end if
end
Add these lines to the invader script:
if myH > cannonLeft and myH < cannonRight then -- directly above cannon
if bullets = [] then
return -- no bullets are available right now so leave handler
end if
set bullet to getAt(bullets,1) -- first available bullet in list
shoot sprite bullet, mysprite -- sends own sprite channel as extra parameter
return -- leave handler
end if
end
This replaces the repeat loops added in the previous lesson, which were regularly testing the shooting property of each bullet, a potential bottleneck, especially if all the bullets are in use much of the time. Similarly, we have managed to move a whole load of hard coded data related to game sprites into one place. Now there are fewer alterations necessary if you change the number of bullets or invaders in your game.
To see this working 'in the abstract', open the Watcher window and type
the invaders of sprite 2
in the field at the top, then press return or click on the add button. When you run the movie you will see a list appearing in the watcher window containing the invader sprite channels.

As you shoot in the invaders, (and whether or not you use the bullet in sprite channel 2), you will see the list will contain fewer and fewer items. All the bullets are using the same list, so if one bullet removes in invader from the list, all the others have fewer invaders also.
In a later lesson, we will see how the connector sprite can gather the sprite information intelligently, clearing up most of its own hardcoding altogether.
Finally, let's just add a little something to the bullet script so that you can feel how things are progressing.
-- new exitframe handler for the bullet script
on exitFrame me
if not shooting then
return
end if
set myV to the locV of sprite mySprite
if myV < 0 or myv > the height of the rect of the stage then
set shooting to false
set the locV of sprite mysprite to offstage
add bullets, mysprite -- ready again, so adds itself to shared list
return
end if
if vdirection = 1 then
set possibleTargets to [cannon]
else
set possibleTargets to invaders
end if
repeat with target in possibleTargets
if sprite mysprite intersects target then
hit sprite target
if target = cannon then
-- End of life
else
deleteOne invaders, target
if invaders = [] then
-- End of level
alert "All invaders dispatched, commander!"
end if
end if
set shooting to false
set the locV of sprite mysprite to offstage
add bullets, mysprite -- ready again, so adds itself to shared list
return
end if
end repeat
set the locV of sprite mySprite to myV + (vdirection * speed)
end
That was a long and complicated lesson. It might be that you need to read through it again to check that you understand what is going on. You might like to download a director movie which contains the working code so far: