• Bruce

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


245 views0 comments

Want to support my work?....Buy my games!

aboutME

Hello, I'm Bruce and I write games for old 8bit computers using Jonathan Cauldwell's excellent Multi-Platform Arcade Games Designer (MPAGD)

I've written a few successful* games for the Sinclair ZX Spectrum and MSX platforms that have been (largely) well received with my most recent game - Twenty Four Hour Parsley People scoring a 10 out of 10 on Planeta Sinclair.

In my blog I am sharing lots of the code that I wrote for my games, in a way that you can use in your own games.   I've commented it so that you'll learn some of the techniques I use to create interesting new mechanics and help your games stand out from the pack.

MPAGD includes lots of standard scripts, they're great to get you started, but if you're new (or just rusty) when it comes to writing code, hopefully my tutorials will help you get started and  turn your imagination into awesome 8 bit games!

All my code is free to use and do with as you please, but if you find them useful please feel free to buy me a coffee ...or better still - buy or download my games :)

*successful is a very relative term in 8bit computer games