Minilop Retroware

MPAGD Advanced

Let's stun an enemy by bouncing on his head...and 3 times for a kill!

19 November 2020

Here's a bit of fun. In this tutorial we're going to jazz up the stock 'HORIZONTAL PATROL' script that MPAGD ships with and make it possible to stun the enemy if we jump on its head....and if we do it three times in a row...we kill him, turn him into a skeleton and let him float up into the ether. Along the way we'll learn some useful tips for handling sprite TYPE switching and we'll be using READ and DATA for varying some sprite movement.

Hopefully we should end up with something like this...

So, a few things to note:

Here's the code for the enemy knight:

ANIMATE

IF DIRECTION = LEFT                        ; set the direction to left
   SPRITELEFT                              ; move left
   IF CANGOLEFT                            ; can we go left?   
      SUBTRACT 16 FROM X                   ; if so look 16px to the left
      IF CANGODOWN                         ; if we were there would we be able to go down?
         LET DIRECTION = RIGHT             ; if so change the direction to right
      ELSE                                 ; if we wouldnt be able to go down
         IF X <= LEFTEDGE                  ; check if we are at the left edge
            LET DIRECTION = RIGHT          ; if we are, then change the direction to right
         ENDIF
      ENDIF
      ADD 16 TO X                          ; reset x to its original value

   ELSE                                    ; if we cant go left
      LET DIRECTION = RIGHT                ; go right
   ENDIF
ENDIF
   

IF DIRECTION = RIGHT                       ; set direction to right
   IF CANGORIGHT                           ; can we go right?
      SPRITERIGHT                          ; yes...go right then
      ADD 16 TO X                          ; look 16px to the right
      IF CANGODOWN                         ; if we were there, would we be able to go down?
         LET DIRECTION = LEFT              ; if so, change direction to left
      ELSE                                 ; if not
         IF X >= RIGHTEDGE                 ; check if we would be at the right edge
            LET DIRECTION = LEFT           ; if we are, change direction to left
         ENDIF
      ENDIF
      SUBTRACT 16 FROM X                   ; reset x to its original value
   ELSE
      LET DIRECTION = LEFT                 ; if we cant go right, go left
   ENDIF
ENDIF
     


IF COLLISION PLAYER                        ; have we collided with the player?
   IF G <= Y 				               ; is the player above us?
      SUBTRACT G FROM Y                    ; if so - by how much?
      IF Y >= 14                           ; more than 14 pixels?
	     IF DIRECTION < 3                  ; is our direction less than 3? (not stunned)
            LET SETTINGB = DIRECTION       ; remember what direction I was going in SETTINGB
            LET DIRECTION = 3              ; if so, make it 3 (anything 3 or above is stunned)
         ELSE                              ; if it was already above 3
            ADD 1 TO DIRECTION             ; add 1 to direction
         ENDIF                  
         OTHER                             ; switch to the player sprite
         STOPFALL                          ; stop the player on my head
         BEEP 80                           ; make a sound
         JUMP 6                            ; make the player jump
         ENDSPRITE                         ; switch back to tme
      ELSE                                 ; if the player is less than 14px above me when he hit me, the stun has failed
         OTHER                             ; switch to the player
         JUMP 2                            ; make the player do a little jump
         ENDSPRITE                         ; switch back to me
         SUBTRACT 1 FROM E                 ; inflict damage on the player
         BEEP 25                           ; make a damage sound
         ENDIF                             
      ENDIF
      ADD G TO Y                           ; reset the sprites y position
   ENDIF
ENDIF  


IF DIRECTION >= 3                          ; if I am stunned
   ADD 1 TO SETTINGA					   ; increment the stun timer							
   IF SETTINGA = 60                        ; is the stun time complete?
      LET DIRECTION = SETTINGB             ; if so start me moving in the direction I was going when I got stunned
      LET SETTINGA = 0                     ; reset the stun timer
   ENDIF  
   IF DIRECTION = 5                        ; have I been bounced on 3 times?
      LET IMAGE = 23                       ; if so, change me to my skeleton image
      LET TYPE = 8                         ; change my type to 8
      LET FRAME = 0                        ; change my frame to 0
	  LET SETTINGA = 0                     ; reset my SETTINGA to 0
   ENDIF
ENDIF

If you are familiar with the standard MPAGD horizontal patrol the first half of the script is pretty much the same, in essence it checks the enemy can move in a direction and isn't going to hit a wall, the edge of the screen or fall off the edge of a platform. The stock routine uses DIRECTION = LEFT and DIRECTION= RIGHT although, in reality, these are stored as numbers 0 and 1.

We are going to take advantage of this by using the number 3 (and above) to indicate the sprite has been stunned.

First we check if the player collides when they are above the enemy, by at least 14 pixels. Anything lower than this will be a failed stun and the player will be punished. As in previous tutorials I'm assuming you are using a couple of Global Variables to store the players X and Y (I use F and G).

You could make the test for a successful Stun a bit more challenging by testing the players X position (F) against the enemies X to see if they are directly (or nearly) above the enemy when they collide...but I'm keeping it simple.

Each time the player bounces on the enemies head we increment DIRECTION, so that when it hits 5 (the third bounce) we start the kill routine.

At this point I change the sprites IMAGE (to a Skeleton), its TYPE, and I also reset the FRAME to 0 and its SETTINGA to 0.

I need to do this because of an important characteristic of MPAGD when we switch a Sprites TYPE. Basically all of its parameters are switched to the new TYPE. Now, my knight sprite has 2 frames (0 and 1), whereas my Skeleton sprite has only 1. You might think that I could overcome this by adding the correct parameters into the SPRITE INITIALISATION script, but TYPE switching does not initialise a new sprite, it simply changes its TYPE. So if I was on FRAME 1 right before the Knight became a Skeleton, the Skeleton would try to display FRAME 1...which doesn't exist, and would get confused and display garbage or another sprite frame entirely.

Similarly, as both of the scripts for the knight and the skeleton use SETTINGA, I need to reset it to 0 before switching.

Right, with that out the way, lets have a look at the Skeleton script:

IF IMAGE 23                   ; am I a skeleton?                 
   SPRITEINK 7                ; cool! make me white
   ADD 1 TO SETTINGA          ; increment the timer by 1
   IF SETTINGA >= 30          ; have we reached 30 yet?
      READ DIRECTION          ; get the next value in the DATA and set it in my DIRECTION
   ENDIF
                              ; check my DIRECTION value
   IF DIRECTION = 1           ; if it's 1
      SPRITERIGHT             ; move me right and up
	  SPRITEUP
   ENDIF
  
   IF DIRECTION = 2           ; if it's 2
      SPRITEUP                ; move me up
   ENDIF
  
   IF DIRECTION = 3           ; if it's 3 
      SPRITELEFT              ; move me left and up
	  SPRITEUP
   ENDIF
  
   ADD 8 TO Y                 ; check 8 pixels from the top of me
   IF Y <= TOPEDGE            ; is it at the top of the screen
      REMOVE                  ; if so, remove me
   ENDIF
   SUBTRACT 8 FROM Y          ; reset my Y value
  
   DATA 1 1 2 2 2 2 3 3 3 3 3 2 2 2 1 1
ENDIF

This is pretty straightforward. We start with a little timer so that the skeleton doesn't move for a second or so, then we have a series of potential directions that the sprite can move, we then change the DIRECTION value by reading the next value from the DATA each time we cycle through the code. BY change the DATA values or adding new pattern statements, we can add interesting movements to our sprites.

Finally, we check where the sprite is, to see if he is moving off the top of the screen before removing him.

And that's its, stunning enemies and floaty skeletons....huzzah!

All MPAGD Advanced