Minilop Retroware

MPAGD Avançado

Vamos atordoar um inimigo a saltar-lhe na cabeça... e matá-lo à terceira!

19 de novembro de 2020

Aqui está algo divertido. Neste tutorial vamos dar mais graça ao script padrão 'HORIZONTAL PATROL' que vem com o MPAGD e tornar possível atordoar o inimigo se saltarmos para a cabeça dele....e se o fizermos três vezes seguidas...matamo-lo, transformamo-lo num esqueleto e deixamo-lo flutuar até ao éter. Pelo caminho vamos aprender algumas dicas úteis para lidar com a troca de TYPE dos sprites e vamos usar READ e DATA para variar algum movimento de sprites.

Com sorte, vamos acabar com algo assim...

Então, algumas coisas a ter em conta:

Este é o código do cavaleiro inimigo:

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

Se estás familiarizado com a patrulha horizontal padrão do MPAGD, a primeira metade do script é praticamente igual: em essência, verifica se o inimigo se pode mover numa direcção e se não vai bater numa parede, no limite do ecrã ou cair do bordo de uma plataforma. A rotina padrão usa DIRECTION = LEFT e DIRECTION= RIGHT embora, na realidade, sejam guardados como os números 0 e 1.

Vamos aproveitar isto usando o número 3 (e superiores) para indicar que o sprite foi atordoado.

Primeiro verificamos se o jogador colide estando acima do inimigo, em pelo menos 14 pixels. Qualquer coisa mais baixa será um atordoamento falhado e o jogador será castigado. Tal como em tutoriais anteriores, estou a assumir que estás a usar algumas variáveis globais para guardar o X e o Y do jogador (eu uso F e G).

Podias tornar o teste de um atordoamento bem-sucedido um pouco mais desafiante testando a posição X do jogador (F) contra o X do inimigo, para ver se está mesmo (ou quase) acima do inimigo quando colidem...mas vou manter as coisas simples.

Cada vez que o jogador salta para a cabeça do inimigo incrementamos DIRECTION, de modo que quando chega a 5 (o terceiro salto) iniciamos a rotina de morte.

Neste ponto mudo a IMAGE do sprite (para um esqueleto), o seu TYPE, e também reponho o FRAME a 0 e o seu SETTINGA a 0.

Preciso de fazer isto por causa de uma característica importante do MPAGD quando mudamos o TYPE de um sprite. Basicamente, todos os seus parâmetros passam para o novo TYPE. O meu sprite de cavaleiro tem 2 frames (0 e 1), ao passo que o meu sprite de esqueleto só tem 1. Podias pensar que eu resolvia isto adicionando os parâmetros correctos ao script de SPRITE INITIALISATION, mas a troca de TYPE não inicializa um sprite novo, apenas muda o seu TYPE. Por isso, se eu estivesse no FRAME 1 mesmo antes de o cavaleiro se tornar esqueleto, o esqueleto tentaria mostrar o FRAME 1...que não existe, ficaria confuso e mostraria lixo ou outro frame de sprite completamente diferente.

Do mesmo modo, como tanto o script do cavaleiro como o do esqueleto usam SETTINGA, preciso de o repor a 0 antes da troca.

Muito bem, com isso esclarecido, vamos dar uma vista de olhos ao script do esqueleto:

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

Isto é bastante simples. Começamos com um pequeno temporizador para que o esqueleto não se mova durante um segundo ou assim, depois temos uma série de direcções possíveis em que o sprite se pode mover, e a seguir mudamos o valor de DIRECTION lendo o valor seguinte de DATA de cada vez que percorremos o código. Ao mudar os valores de DATA ou adicionar novas instruções de padrão, podemos dar movimentos interessantes aos nossos sprites.

Por fim, verificamos onde está o sprite, para ver se está a sair pela parte de cima do ecrã antes de o removermos.

E é isto: inimigos atordoados e esqueletos flutuantes....viva!

Todo o MPAGD Avançado