So far, Stinky Dog can move left and right, move up and down ladders, and JUMP. That's five keys. But how about we give him a super power? I'm thinking we give him the ability to do noxious farts, those farts then rise up the screen...and perhaps knock our enemy, Sideways Clive out...or some such nonsense.
First, let's create a new fart sprite (no-one ever said this was going to be a high-brow game). This should do the trick:
Now, were going to need a new key press test in our Player event to, well, do a fart... we'll use the 1 key and we'll bind it to FIRE2, from the Editor menu select: Keyboard Controls, click the FIRE2 box and press your 1 Key:
Next we'll open up our PLAYER EVENT, and add some code to unleash the fart...drop this in beneath the IF statement that controls the JUMP (beneath its ENDIF)
IF KEY FIRE2 ; is the FIRE2 key being pressed?
SPAWN 2 4 ; SPAWN a fart (TYPE 2, IMAGE 4)
ENDIF
SPAWN has two arguments, the first dictates the TYPE (which we can then code in the 'Sprite Type 2' event, and the Sprite IMAGE that will be spawned (in my example it's image is number 4, obviously you can change these dependent on your game.
Let's test the game and see what happens.
OK, unsurprisingly that did not go well.
There's a few lessons here.
When our Player Sprite spawns another sprite, the new sprite is Spawned at the same X & Y position as the Player
If you keep your finger on the FIRE2 button it will keep spawning new sprites. And MPAGD can only handle 12 sprites on screen at any one time.
So, we're going to need to put some controls in place:
We will limit Stinky Dog to only being able to have one active fart at any one time
We need the fart to be spawned from his rear end!
First, we will create a new variable, F, which will track whether or not there is a fart 'in play', we will reset it to 0 (no fart in play) in our RESTARTSCREEN event with a simple:
LET F = 0 ; when we start a screen, there is no fart in play
Then, in a player event we will extend our FIRE2 code to only spawn a fart when F is 0
IF KEY FIRE2 ; is the FIRE2 key being pressed?
IF F = 0 ; if there is no fart in play
SPAWN 2 4 ; SPAWN a fart (TYPE 2, IMAGE 4)
LET F = 1 ; there is now a fart in play
ENDIF
ENDIF
So now, when we test the game, Stinky dog will do a solitary fart, because we set F to 1 immediately after the spawn to prevent another bout of flatulence.
But it's still spawning directly over Stinky Dog.
Now, remember back to when we edited the player scripty back in Part 14 we added a line of code in the going left and going right clauses:
LET DIRECTION = LEFT
LET DIRECTION = RIGHT
We did this so that we would remember which direction Stinky dog is facing & travelling.
So we can use this, to reposition the fart. Let's enhance of FIRE2 code some more:
IF KEY FIRE2 ; is the FIRE2 key being pressed?
IF F = 0 ; if there is no fart in play
IF DIRECTION = LEFT ; if Stinky Dog is facing Left
ADD 16 TO X ; set X 16 pixels to the right
SPAWN 2 4 ; SPAWN a fart (TYPE 2, IMAGE 4)
SUBTRACT 16 FROM X ; reset X to its original position
LET F = 1 ; there is now a fart in play
ELSE
IF DIRECTION = RIGHT ; if Stinky Dog is facing Right
SUBTRACT 16 FROM X ; set X 16 pixels to the left
SPAWN 2 4 ; SPAWN a fart (TYPE 2, IMAGE 4)
ADD 16 TO X ; reset X to its original position
LET F = 1 ; there is now a fart in play
ENDIF
ENDIF
ENDIF
ENDIF
As the program runs sequentially through each event, we are able to manipulate Stinky Dogs X value, spawn the fart, and reset the X value so that Stinky dog himself wont move.
Test your game again, hopefully this happens...
A fart is released from the back side of Stinky dog. But it just sits there. Doing nothing. Let's head to our SPRITE TYPE 2 EVENT.
The way I want it to work is:
Stinky Dog farts
The fart lingers for a short while
The fart rises up the screen
If the fart hits our enemy, Sideways Clive, he is knocked out for a short while and stops moving
So far we've achieved part 1, lets take a look at parts 2 & 3.
We're going to need a timer that will count for, say, 1 second. This timer is going to be local to the fart, so we can use one of the sprite-specific variables, I'm going to use SETTINGA.
Now, MPAGD runs at 25 frames per second, so if we increment SettingA by 1, it should take about 1 second to reach 25.
When it reaches 25 we want it to start moving up the Screen. Here's how we can achieve all this:
IF SETTINGA < 25 ; IF SETTINGA is less than 25
ADD 1 TO SETTINGA ; increment it
ELSE ; otherwise if it is 25
SPRITEUP ; move the fart upwards
ENDIF
Let's give it a test:
Ok, it's kind of working, the fart keeps going up the screen, but when it reaches the top it wraps and appears at the bottom again.
Let's add some more code that will remove the fart when it reaches the top, and allows Stinky Dog to drop another!
We'll add this to our SPRITE TYPE 2 event:
IF Y <= TOPEDGE ; if the fart reaches the top of the play area
REMOVE ; remove the fart
LET F = 0 ; reset F to No Fart in Play
ENDIF
Remember that, unlike a graph, the Spectrums Y axis is 0 at the top, not the bottom. So when the Fart's Y reaches the TOPEDGE we will REMOVE the sprite and reset our Fart in Play (F) variable to 0, meaning there is no longer one on the screen.
OK, so now we've written the code for the Fart, we need to turn our attention to what happens when it hits Sideways Clive. We want to knock him out for a while and stop him moving.
Let's look at Sideways Clive's code that we let MPAGD generate for us back in Part 10 , I've added comments to it it to help you understand each line:
IF DIRECTION = LEFT ; if direction is set to left
IF CANGOLEFT ; and there is nothing in the way
SPRITELEFT ; move sideways clive left
SUBTRACT 16 FROM X ; check 16 pixels to the left of clive
IF CANGODOWN ; would he be able to go down there?
LET DIRECTION = RIGHT ; if so change direction to RIGHT
LET IMAGE = 2 ; make sure we are on image 2
LET FRAME = 0 ; and make sure its the first frame
ENDIF
ADD 16 TO X ; reset x to its original value
ELSE ; if he cant go left
LET DIRECTION = RIGHT ; change direction to right
LET IMAGE = 2 ; make sure we are on image 2
LET FRAME = 0 ; and make sure its the first frame
ENDIF
ELSE ; if DIRECTION isnt left, it must be RIGHT
IF CANGORIGHT ; if clive can go right (
SPRITERIGHT ; go right
ADD 16 TO X ; check 16 pixels to the right of clive
IF CANGODOWN ; if he was there, would he fall down?
LET DIRECTION = LEFT ; if so, change direction to left
LET IMAGE = 2 ; make sure we are on image 2
LET FRAME = 0 ; and make sure its the first frame
ENDIF
SUBTRACT 16 FROM X ; reset X to its original value
ELSE ; if he can't go right
LET DIRECTION = LEFT ; change direction to left
LET IMAGE = 2 ; make sure we are on image 2
LET FRAME = 0 ; and make sure its the first frame
ENDIF
ENDIF
ANIMATE ; cycle through Clives frames to animate him
IF COLLISION PLAYER ; if Clive touches Stinky Dog
KILL ; Kill Stinky Dog
ENDIF
Now, hopefully you'll notice there is a lot of repetition in there that actually, we don't need. And I advise you to always try and be as economical with your code as possible. The code above assumes you have different images for facing left and facing right (like Stinky Dog), but Sideways Clive always faces forward ...and shuffles sideways from left to right. So immediately we can strip out all those LET IMAGE = 2, LET FRAME = 0 lines and save ourselves a few bytes:
IF DIRECTION = LEFT ; if direction is set to left
IF CANGOLEFT ; and there is nothing in the way
SPRITELEFT ; move sideways Clive left
SUBTRACT 16 FROM X ; check 16 pixels to the left of Clive
IF CANGODOWN ; would he be able to go down there?
LET DIRECTION = RIGHT ; if so change direction to RIGHT
ENDIF
ADD 16 TO X ; reset x to its original value
ELSE ; if he cant go left
LET DIRECTION = RIGHT ; change direction to right
ENDIF
ELSE ; if DIRECTION isn't left, it must be RIGHT
IF CANGORIGHT ; if Clive can go right (
SPRITERIGHT ; go right
ADD 16 TO X ; check 16 pixels to the right of Clive
IF CANGODOWN ; if he was there, would he fall down?
LET DIRECTION = LEFT ; if so, change direction to left
ENDIF
SUBTRACT 16 FROM X ; reset X to its original value
ELSE ; if he can't go right
LET DIRECTION = LEFT ; change direction to left
ENDIF
ENDIF
ANIMATE ; cycle through Clive's frames to animate him
IF COLLISION PLAYER ; if Clive touches Stinky Dog
KILL ; Kill Stinky Dog
ENDIF
So, as it stands, if DIRECTION is LEFT Clive will go LEFT and if DIRECTION is RIGHT he will go right.
We're going to create a new direction, called STUNNED
If Clive is STUNNED he won't move at all.
First, we will add some collision code:
IF COLLISION 2 ; if Clive touches a Type 2 sprite (the fart)
IF DIRECTION = LEFT ; if Clive is going left
LET SETTINGB = 0 ; remember the direction he was going, 0 = Left
ELSE ; if he wasn't going left
LET SETTINGB = 1 ; he was going RIGHT, 1 = RIGHT
ENDIF
LET DIRECTION = 5 ; set the direction to STUNNED
LET SETTINGA = 0 ; start the stunned timer
OTHER ; switch to the Fart
REMOVE ; remove the fart
ENDSPRITE ; switch back to this event
LET F = 0 ; reset the Fart in play to no fart in play
ENDIF
A couple of things to note here, first, we cant use any old label for DIRECTION, LEFT,RIGHT, UP & DOWN are allowable, but we cant used STUNNED, so we'll use the value 5 to indicate when Clive is stunned.
Second, we've introduced the command OTHER, this allows you to switch to the other sprite involved in the collision, in this case the fart and perform some action on it, in our case we REMOVE it. The ENDSPRITE command will tell MPAGD to return back to this event - handle OTHER with care, it can slow your game down if you do too much - and always finish it with ENDSPRITE.
Now we'll adapt our movement code to allow for Stunning ...
IF DIRECTION = LEFT ; if direction is set to left
SPRITEINK 71
IF CANGOLEFT ; and there is nothing in the way
SPRITELEFT ; move sideways Clive left
SUBTRACT 16 FROM X ; check 16 pixels to the left of Clive
IF CANGODOWN ; would he be able to go down there?
LET DIRECTION = RIGHT ; if so change direction to RIGHT
ENDIF
ADD 16 TO X ; reset x to its original value
ELSE ; if he cant go left
LET DIRECTION = RIGHT ; change direction to right
ENDIF
ELSE ; if DIRECTION isn't left
IF DIRECTION = RIGHT ; is it RIGHT, if so...
SPRITEINK 71
IF CANGORIGHT ; if Clive can go right (
SPRITERIGHT ; go right
ADD 16 TO X ; check 16 pixels to the right of Clive
IF CANGODOWN ; if he was there, would he fall down?
LET DIRECTION = LEFT ; if so, change direction to left
ENDIF
SUBTRACT 16 FROM X ; reset X to its original value
ELSE ; if he cant go right any more
LET DIRECTION = LEFT ; change direction to left
ENDIF
ELSE
IF DIRECTION = 5 ; if clive is stunned
SPRITEINK 67 ; change him to magenta
ADD 1 TO SETTINGA ; increment the stun timer
IF SETTINGA = 100 ; when timer reaches 100
IF SETTINGB = 0 ; if previously he was going left
LET DIRECTION = LEFT ; go left
ELSE ; otherwise
LET DIRECTION = RIGHT ; go right
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
As you can see, I have extended the main IF...ELSE...ENDIF Clause to allow for what should happen when DIRECTION = 5 (i.e. when Clive is stunned): we change him from white to magenta, increment a 4 second timer, at the end of which he will continue in his previous direction of travel.
Finally, to round it all off, now that in the code we can tell, at any time, whether Clive is stunned or not, let's change the collision with the player (stinky dog) code so that, Clive can't kill Stinky Dog if he is stunned, we can achieve this simply by changing it to:
IF COLLISION PLAYER ; if Clive touches Stinky Dog
IF DIRECTION <> 5 ; and if Clive is not stunned
KILL ; Kill Stinky Dog
ENDIF
ENDIF
OK, let's give it a spin...
Is it just me or do we have the beginning of something not entirely crap here?!
I appreciate this has been a long tutorial, so for reference, here are the complete events we have been working with for you to cross reference with yours:
EVENT PLAYER
;===============STINKY DOG=================
IF KEY LEFT ; Is the left key pressed?
LET DIRECTION = LEFT ; if so, remember I am going LEFT
LET IMAGE = 1 ; display the left facing image
IF X <= LEFTEDGE ; are we at the left edge of the screen?
SCREENLEFT ; if so, go to the screen to left on the map
LET X = RIGHTEDGE ; and put me at the right edge of that screen
EXIT ; and stop processing this event
ELSE ; if I'm not at the left edge
IF CANGOLEFT ; is there space to the left of me?
SPRITELEFT ; if so move me left
ANIMATE ; and animate me
ENDIF
ENDIF
ENDIF
IF KEY RIGHT ; Is the right key pressed?
LET DIRECTION = RIGHT ; if so, remember I am going RIGHT
LET IMAGE = 0 ; display the right facing image
IF X >= RIGHTEDGE ; Am I at the right edge of the screen?
SCREENRIGHT ; if so go to the screen to right on the map
LET X = LEFTEDGE ; and put me at the left edge
EXIT ; and stop processing this event
ELSE ; if I'm not at the right edge
IF CANGORIGHT ; is there space to the right of me?
SPRITERIGHT ; if so, move me right
ANIMATE ; and animate me?
ENDIF
ENDIF
ENDIF
IF KEY UP ; is the UP key pressed?
ANIMATE SLOW ; if so, animate me slowly
IF LADDERABOVE ; is there a ladder above me?
IF CANGOUP ; can I go up?
LET IMAGE = 3 ; display the image of me climbing
SPRITEUP ; move me up
LET DIRECTION = UP ; remember I am going up
ELSE ; if there is a ladder above me, but I cant go up
ADD 1 TO Y ; nudge me 1 pixel to the right
ENDIF
ELSE ; if there isn't a ladder above me
SPRITELEFT ; move me left
IF LADDERABOVE ; now is there a ladder above me?
ELSE ; if not
SPRITERIGHT ; move me back where I was
SPRITERIGHT ; then a bit more to the right
IF LADDERABOVE ; now is there a ladder above me?
ELSE ; if not
SPRITELEFT ; move me back where I was
ENDIF
ENDIF
ENDIF
ENDIF
IF KEY DOWN ; is the DOWN key pressed?
ANIMATE SLOW ; if so, animate me slowly
IF LADDERBELOW ; is there a ladder below me?
LET IMAGE = 3 ; if so, set my image to the climbing one
SPRITEDOWN ; move me down
LET DIRECTION = DOWN ; remember I am going down
ELSE ; if there isn't a ladder below me
SPRITELEFT ; move me left
IF LADDERBELOW ; is there a ladder below me now?
ELSE ; if not
SPRITERIGHT ; move me back where I was
SPRITERIGHT ; then a bit more to the right
IF LADDERBELOW ; now is there a ladder below me?
ELSE ; if not
SPRITELEFT ; move me back where I was
ENDIF
ENDIF
ENDIF
ENDIF
IF KEY FIRE ; is the Fire key being pressed?
JUMP 7 ; if so, make me Jump to height 7
ENDIF
IF KEY FIRE2 ; is the FIRE2 key being pressed?
IF F = 0 ; if there is no fart in play
IF DIRECTION = LEFT ; if Stinky Dog is facing Left
ADD 16 TO X ; set X 16 pixels to the right
SPAWN 2 4 ; SPAWN a fart (TYPE 2, IMAGE 4)
SUBTRACT 16 FROM X ; reset X to its original position
LET F = 1 ; there is now a fart in play
ELSE
IF DIRECTION = RIGHT ; if Stinky Dog is facing Right
SUBTRACT 16 FROM X ; set X 16 pixels to the left
SPAWN 2 4 ; SPAWN a fart (TYPE 2, IMAGE 4)
ADD 16 TO X ; reset X to its original position
LET F = 1 ; there is now a fart in play
ENDIF
ENDIF
ENDIF
ENDIF
FALL ; make me fall if there is nothing below me
IF DEADLY ; am I touching something deadly?
KILL ; if so, kill me
ENDIF
GETBLOCKS ; if I touch any collectible blocks, run the Collected Block script
EVENT SPRITETYPE1
;============SIDEWAYS CLIVE==================================
IF DIRECTION = LEFT ; if direction is set to left
SPRITEINK 71 ; BRIGHT WHITE
IF CANGOLEFT ; and there is nothing in the way
SPRITELEFT ; move sideways Clive left
SUBTRACT 16 FROM X ; check 16 pixels to the left of Clive
IF CANGODOWN ; would he be able to go down there?
LET DIRECTION = RIGHT ; if so change direction to RIGHT
ENDIF
ADD 16 TO X ; reset x to its original value
ELSE ; if he cant go left
LET DIRECTION = RIGHT ; change direction to right
ENDIF
ELSE ; if DIRECTION isn't left
IF DIRECTION = RIGHT ; is it RIGHT, if so...
SPRITEINK 71 ; BRIGHT WHITE
IF CANGORIGHT ; if Clive can go right (
SPRITERIGHT ; go right
ADD 16 TO X ; check 16 pixels to the right of Clive
IF CANGODOWN ; if he was there, would he fall down?
LET DIRECTION = LEFT ; if so, change direction to left
ENDIF
SUBTRACT 16 FROM X ; reset X to its original value
ELSE ; if he cant go right any more
LET DIRECTION = LEFT ; change direction to left
ENDIF
ELSE
IF DIRECTION = 5 ; if clive is stunned
SPRITEINK 67 ; change him to magenta
ADD 1 TO SETTINGA ; increment the stun timer
IF SETTINGA = 100 ; when timer reaches 100
IF SETTINGB = 0 ; if previously he was going left
LET DIRECTION = LEFT ; go left
ELSE ; otherwitse
LET DIRECTION = RIGHT ; go right
ENDIF
ENDIF
ENDIF
ENDIF
ENDIF
ANIMATE ; cycle through Clives frames to animate him
IF COLLISION PLAYER ; if Clive touches Stinky Dog
IF DIRECTION <> 5 ; and if Clive is not stunned
KILL ; Kill Stinky Dog
ENDIF
ENDIF
IF COLLISION 2 ; if Clive touches a Type 2 sprite (the fart)
IF DIRECTION = LEFT ; if Clive is going left
LET SETTINGB = 0 ; remember the direction he was going, 0 = Left
ELSE ; if he wasn't going left
LET SETTINGB = 1 ; he was going RIGHT, 1 = RIGHT
ENDIF
LET DIRECTION = 5 ; set the direction to STUNNED
LET SETTINGA = 0 ; start the stunned timer
OTHER ; switch to the Fart
REMOVE ; remove the fart
ENDSPRITE ; switch back to this event
LET F = 0 ; reset the Fart in play to no fart in play
ENDIF
EVENT SPRITETYPE2
;============FART==================================
IF SETTINGA < 25
ADD 1 TO SETTINGA
ELSE
SPRITEUP
ENDIF
IF Y <= TOPEDGE ; if the fart reaches the top of the play area
REMOVE ; remove the fart
LET F = 0 ; reset F to No Fart in Play
ENDIF
Comments