Bruce

Oct 13, 202113 min

Let's create an MPAGD game - Part 16: SPAWNing a super power for Stinky Dog

Updated: Oct 30, 2021

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:

  1. We will limit Stinky Dog to only being able to have one active fart at any one time

  2. 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:

  1. Stinky Dog farts

  2. The fart lingers for a short while

  3. The fart rises up the screen

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

NEXT: PART 17: Creating OBJECTs

    7170
    6