Back to Lesson 15
Forward to Lesson 17

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:

.zip archive

.sit.hqx archive.



Forward to Lesson 17