Back to Lesson 12
Forward to Lesson 14

Invadir 13 - Caught in the Crossfire

IF YOU HAVE NOT TIDIED UP YOUR SCRIPTS AND MADE PREPARATIONS FOR THE NEXT STEPS AS SUGGESTED IN THE PREVIOUS LESSON, PLEASE GO BACK AND DO SO NOW!

Sorry to shout, but we're about to introduce some extra complexity into the game and if you are to retain your sanity and sense of self worth it is important that as many loose ends are tied up as possible before the new stuff throws the whole thing out of control.

The next step is to refine the bullet script so that it can be fired from both the cannon and the invaders. We'd also like to have more than one bullet. It has taken me some time to put my thoughts in order about presenting this next part of the tutorial. Those of you who have watched the tutorial appear lesson by lesson may already have attempted to implement multiple bullets yourself in the interim. You will probably have found it quite complicated.

Do not be afraid of complexity.

One of the main reasons for choosing an object-oriented approach is that it formalises the process of managing complex systems. You have already seen this in action with the invaders. Before you started this tutorial you might have imagined that a space invader game would require long complicated handlers which 'keep track of' all the necessary information, the speed and direction of each invader for example. As it happens we've let Director's existing abstraction of multiple sprite channels (a list) deal with that so that we only need to think about one invader to program all of them.

Encapsulation removes 'keeping track' from the equation, indeed if you are having trouble keeping track of what is going on, you have probably not encapsulated things optimally.

Now, we know that the bullet will need to be moving in two directions, depending on which sprite shoots it. What we'll do is vary the bullet's new vdirection property, then use a parameter to specify where the bullet is coming from, thus:

-- new shoot handler for the bullet script

on shoot me, whosShooting

  if shooting then

    return

  end if

  set shooting to true
  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

Notice the whosShooting parameter which is expected along with the shoot message. This provides the starting location for the bullet and also specifies the direction.then when it comes to testing for collisions, it will be necessary to test different sprite channels depending on the direction. In the previous lesson I mysteriously changed the property name 'possibleTargets' to 'invaders' and added an extra line to the exitframe handler to set the local variable possibleTargets to the invaders list. Now you are going to see why I did that. Look at this;

-- 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

    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

        end if

      end if

      set shooting to false

      set the locV of sprite mysprite to offstage

      return

    end if

  end repeat

  set the locV of sprite mySprite to myV + (vdirection * speed)

end

So now, it is important to specify where the bullets are coming from. Go back to your cannon script and provide the extra parameter:

  if the shiftDown then

    shoot sprite bullet, mysprite -- sends own sprite channel as extra parameter

  end if

If you run the movie now you should find that everything works exactly as before. This might be a bit disheartening after all our efforts, but I also hope you are beginning to see why we took the trouble to tidy up. Don't worry, we'll soon reap a rich harvest from all this.

For some immediate lollipops, we can get the invaders to shoot downwards without too much trouble. This is a quick fix for those impatient souls who want to see something new happening after this difficult and slightly anal exercise in order:

In true 'quick and dirty' style I'm going to use hardcoded values for this. I'll clean up in the next lesson:

-- very temporary exitframe handler for the invader script

on exitFrame me

  if not alive then

    return -- leave here, do nothing

  end if

  set myH to the locH of sprite mySprite -- current horizontal pos

  if myH < 0 then -- hit left edge

    set hdirection to 1

  end if

  if myH > stagewidth then -- hit right edge

    set hdirection to -1

  end if

  set the locH of sprite mySprite to myH + (hdirection * speed) -- move sprite
  set cannonLeft to the left of sprite 1 -- YIKES! HARDCODED!
  set cannonRight to the right of sprite 1 -- WORSE, THE SAME VALUE AGAIN!

  if myH > cannonLeft and myH < cannonRight then -- directly above cannon

    shoot sprite 2, mysprite -- Urrgh. But it works!

  end if

end

This should ensure that the bullet drops down from the invader when it is in line with the cannon. If you're lucky, you can 'steal' the bullet if you are lucky by holding down the shift key. When a baddies bullet hits the cannon there will be an error message:

Script Error: Handler not defined

  hit sprite target

#hit

This is a nerdy way of telling you that everything is going ok. The cannon does not understand the #hit message, but at least it has recieved it.

I hope that is gratifying enough to feel like we have not been totally wasting our time! Now read on...

Forward to Lesson 14