Let's create an MPAGD game - Part 26: Improving the KILL PLAYER routine and TYPE switching
I want to add a bit of polish to the game by improving what happens when Stinky Dog is killed.
At the moment, there are three ways Stinky Dog can be killed:
If he collides with Sideways Clive
If he lands on a DEADLY spike block
If the air in the room becomes too toxic
And when Stinky Dog is killed, he just respawns at his original position.
Let's make it a bit more interesting, we'll add a sound and an animation.
The animation will be a Tombstone that appears out of the ground.
I'm going to create a 4 Frame sprite for the Tombstone.
First I designed the full Tombstone, in the Sprite Editor press X to add a new Sprite
Next, I'm going to copy and paste this frame 3 times, this will give me four identical frames for this sprite. To do this, I use the keys:
M - copy the frame
I - insert a new frame
K - paste the frame
I - insert another frame
K - paste the frame into it
I -insert the last frame
K- paste the frame into it
Now we have a 4 framed sprite containing the full tombstone in each frame.
To do this you can use the D and F keys to cycle through your frames ( D back, F forward)
To give the effect of the tombstone rising out of the ground I'm going to need to shift it up 4 pixels at a time, (4 x 4 = 16, our sprite is 16 pixels high)
Make sure you are currently viewing Frame 000 (use D or F to cycle to it if not)
Now press the UP cursor four times
Your sprite should now look like this, what were the top 4 rows are now the bottom four rows.
Now right click on the coloured pixels in the top 12 rows to delete them. Your Frame 0 should now look like this:
When it does, press F to move to the next frame.
This time we need to shift it up 8 pixels, press the up key 8 times then delete the top 8 rows, Frame 1 should now look like:
When it does, press F to move to the next frame.
This time either press the UP cursor 12 times (or the down cursor 4 times) and delete the top 4 rows, it should now look like:
Press F to move to the last frame, this should show the full tombstone, which is what we want, no need to edit it.
Press F again and you should be back at Frame 0. If you've accidentally created additional frames you can press R to remove them.
keep your finger on F and you should see the animation in the preview, it will be quite quick, don't worry about that, we can control the speed in our code.
Now that we have a Tombstone Sprite, we're going to write some code for it. I'm going to put it in SPRITE TYPE 8, from your Events menu select Sprite Type 8.
Here's the code:
EVENT SPRITETYPE8 IF IMAGE 7 ; is it the tombstone FALL ; make it subject to gravity IF FRAME <> 3 ; if we are not on the last frame ANIMATE MEDIUM ; animate the tombstone ELSE LET RND = 5 ; use RND as a temporary variable staring value of 5 REPEAT 20 ; do the following 20 times BEEP RND ; make sound based on current RND DELAY 2 ; a very brief pause ADD 5 TO RND ; increase the BEEP value by 5 ENDREPEAT KILL ; kill the player EXIT ; stop processing this event ENDIF ENDIF
First, I've wrapped everything in an IF IMAGE 7 statement, I've done this as I'm likely to use Type 8 for other non-related sprites in the future, by doing so this code will only run for the Tombstone sprite.
Then I've made it subject to gravity so that it will FALL to the blocks beneath so we shouldnt end up with any mid-air tombstones!
Next I test if we are NOT currently displaying the last sprite. IF FRAME <> 3 means If NOT Frame 3.
And if we are not showing Frame 3 I want the frame to ANIMATE (i.e. cycle through the frames) at MEDIUM speed.
ANIMATE will accept the arguments:
I then have an ELSE, ie. what should happen if we have reached FRAME 3. This will then play a sound. Note that once again I am using RND as a temporary variable to control the sound effect.
Once the sound has run we will KILL the player, this will then trigger the KILL PLAYER routine.
Finally I've added an EXIT command, this will tell MPAGD to cease any further processing of this event. We might not need this, but I tend to put them in when I am likely to have further code in this event in the future that I won't want to run if the player has been killed already.
Next, we're going to need to update our PLAYER EVENT so that we can trigger the tombstone when Stinky Dog is killed. Open up your player event and look for the IF DEADLY statement, this controls what happens when stinky dog touches a deadly block like the spikes in our game. It probably looks like this:
IF DEADLY KILL ENDIF
We're going to change it to this:
IF DEADLY ; am I touching something deadly? LET IMAGE = 7 ; if so, turn me into the tombstone sprite LET FRAME = 0 ; reset me to frame 0 LET TYPE = 8 ; make me a type 8 sprite EXIT ; stop processing this event ENDIF
So, when Stinky Dog touches a deadly spike, we'll change his sprite image to 7 (the tombstone), We will also turn him into a TYPE 8 so that from now on on the TYPE 8 event code will control the tombstone.
Note that I also want to ensure that when we first run the TYPE 8 code we do so from FRAME 0. When you TYPE SWITCH a sprite, all of the variables for your original sprite, including the FRAME number will transfer to the new sprite. As we cant be sure what frame stinky dog was on when he touches a deadly block we want to make sure the tombstone starts from its first frame (FRAME 0).
OK, let's build and test it:
It works!, when Stinky Dog touches a deadly block the tombstone appears and he is killed.
But it doesn't happen when he is killed by Sideways Clive, it also wont happen if the Air Purity meter reaches 0. Because so far we have only switched the sprite type in the IF DEADLY code.
So, we could just add the same code in the COLLISION code that detects when Sideways Clive touches Stinky Dog, and in the code that kills Stinky Dog when the Air Purity reaches 0.
That's a lot of repeated code, and chances are, as our game develops we are going to add new ways to kill Stinky Dog. It would be better then, to write a routine that we can trigger whenever we want to Kill the Dog. The KILL PLAYER event is not the best for this, because in effect we really want to control what happens RIGHT BEFORE we KILL the player in the code.
Better then to keep it in the PLAYER EVENT.
And to do this we are going to use one of the special Sprite Variables to trigger it.
I'm going to use SETTINGA as the variable, this is a LOCAL variable, in that it is unique for each SPRITE. In the Player Event, add the following code:
IF SETTINGA = 99 ; do we want to kill Stinky Dog LET IMAGE = 7 ; if so, turn me into the tombstone sprite LET FRAME = 0 ; reset me to frame 0 LET TYPE = 8 ; make me a type 8 sprite ENDIF
So now, whenever we want to kill to dog, we just need to LET SETTINGA = 99
Now we can update the deadly code to:
IF DEADLY ; am I touching something deadly? LET SETTINGA = 99 ; run the kill code ENDIF
And the air purity test to:
IF P <= 0 ; if air purity is 0 LET SETTINGA = 99 ; run the kill code ENDIF
OK, this is fine for things that we test for in the PLAYER EVENT, but what about the collision detection with Sideways Clive? Because that code is in Clive's event (Sprite Event 1) and that currently looks like this:
IF COLLISION PLAYER ; if Clive touches Stinky Dog IF DIRECTION <> 5 ; and if Clive is not stunned KILL ; Kill Stinky Dog ENDIF ENDIF
As SETTINGA is local to Stinky Dog, we can't just replace the KILL command with LET SETTINGA = 99 in the above code, since that would in effect change Sideways Clive's SETTINGA value to 99. Fortunately, MPAGD has a solution: OTHER...ENDSPRITE.
IF COLLISION PLAYER ; if Clive touches Stinky Dog IF DIRECTION <> 5 ; and if Clive is not stunned OTHER ; switch to Stinky Dog LET SETTINGA = 99 ; run the death code ENDSPRITE ; switch back to Sideways Clive ENDIF ENDIF
OTHER can only be used inside an IF COLLISION statement. It allows us to switch to the OTHER sprite that the current sprite (in this case Clive) is colliding with. We must always switch back to the current sprite using the ENDSPRITE command.
Right, let's test it!
Not bad, now we get the Tombstone, when Stinky Dog touches a DEADLY or Clive and if the air purity reaches 0.
Only problem I can see is Clive continues walking over the tombstone so the graphics overwrite each other and that looks a little messy.
Let's look at how we can improve that.
We'll add some code in Type 1 (Clive):
IF COLLISION 8 ; if we touch a type 8 (tombstone) UNDOSPRITEMOVE ; move clive off the tombstone ENDIF
What this should do is, if Clive collides with a TYPE 8 sprite (like the tombstone), UNDOSPRITEMOVE will undo the move that caused the collision detection and effectively move him off the Tombstone.
That'll do nicely for now!