Lesson 7 - Messages between Objects
Great going so far, although we really want the shoot message to come from somewhere other than the message window. Remember the message window will not be there in the finished product. We also need something easy for the user so that they can shoot quickly. We could use the mouse button, but I'd rather not because if you click outside Director accidentally the movie will stop running and you'll bring some other application to the front. This is irritating (believe me) so it might be better to use the keyboard.
We could get the bullet to check the keyboard when it is not shooting but it might be conceptually better for the cannon to do this and for the shoot message to come from the cannon. We also want the invader to be able to shoot bullets. We can now apply what we now know about properties and the beginsprite message to the cannon script:
property mySprite, bullet
on beginsprite me
set mySprite to the spritenum of me
set bullet to 2
end
on exitFrame me
set stagewidth to the width of the rect of the stage
if the mouseH > 0 and the mouseH < stagewidth then
set the locH of sprite mySprite to the mouseH
end if
if the shiftDown then
shoot sprite bullet
end if
end
When you run the movie you will find that pressing the shift key on the keyboard launches a bullet from the cannon. When the bullet disappears from the screen it is ready to be shot again. Notice that it is the cannon which monitors the state of the shift key (use of non 'modifier' keys is more complicated) and sends a message to the sprite specified by its bullet property. Now we have to turn out attention to collisions between the bullet and its targets so that the invaders can be hit by the bullet.
Director provides several convenient features for collisions and intersections. We are going to use the easiest and most accurate. Let's look again at the exitframe handler of the bullet script.
on exitFrame me
if shooting then
set myV to the locV of sprite mySprite
if myV < 0 then
set shooting to false
set the locV of sprite mysprite to -999
return
end if
set the locV of sprite mySprite to myV - 1
end if
end
After the first test (shooting) has proved true, we therefore know that the bullet is moving. It is at this moment that we test whether the bullet has moved offstage, and it is therefore at this moment that we test for collisions. For now we'll test for collisions with only the first of our invaders, the one in channel 3.
on exitFrame me
if shooting then
set myV to the locV of sprite mySprite
if myV < 0 then
set shooting to false
set the locV of sprite mysprite to -999
return
end if
if sprite mysprite intersects 3 then
hit sprite 3
end if
set the locV of sprite mySprite to myV - 1
end if
end
Once again, we are using a custom message, hit , addressed to sprite 3, but if we run the movie now, a collision between the bullet and the invader in sprite channel 3 will produce an error, 'handler not defined'. This is because the script attached to sprite 3 has no way of handling the message.
There are ways of avoiding the error without adding an extra handler to the invader script, but in this case the error message indicates our next step. We need to get the invader to respond to the hit message by adding the necessary handler. Here is how the invader script will look just after we have added the skeleton for the new hit handler:
property mySprite, hdirection, stagewidth
on beginsprite me
set mySprite to the spritenum of me
set hdirection to 1
set stagewidth to the width of the rect of the stage
end
on exitFrame me
set myH to the locH of sprite mySprite
if myH < 0 then
set hdirection to 1
end if
if myH > stagewidth then
set hdirection to -1
end if
set the locH of sprite mySprite to myH + hdirection
end
on hit me
end
...and if all we wanted was to avoid the 'handler not defined' error, this would do just fine, only we want the invader to stop doing what it was doing and die. This requires something similar to the state variable shooting in the bullet script. We could add a property called alive so that the invader only moved from side to side if alive were true. This is how the script would look if we did this.
property mySprite, hdirection, stagewidth, alive
on beginsprite me
set mySprite to the spritenum of me
set hdirection to 1
set stagewidth to the width of the rect of the stage
set alive to true
end
on exitFrame me
if not alive then
return
end if
set myH to the locH of sprite mySprite
if myH < 0 then
set hdirection to 1
end if
if myH > stagewidth then
set hdirection to -1
end if
set the locH of sprite mySprite to myH + hdirection
end
on hit me
set alive to false
set the locH of sprite mySprite to -999
end
Later we will modify this so that the invader will run a little animation while it is dying. This means that simple alive and not alive will not be adequate to describe the different kinds of behevior we want from the invader.
Now at last we have some gameplay. Run the movie and try and shoot at sprite 3. If you are successful, sprite 3 should disappear. This is fine, but what about the other invaders?