Minilop Retroware

MPAGD Iniciantes · Parte 26 de 29

Vamos criar um jogo com MPAGD, Parte 26: Melhorar a rotina KILL PLAYER e a troca de TYPE

2 de novembro de 2021

Quero dar um pouco de acabamento ao jogo melhorando o que acontece quando o Stinky Dog é morto.

Neste momento, há três formas de matar o Stinky Dog:

  1. Se colidir com o Sideways Clive

  2. Se cair sobre um bloco de picos DEADLY

  3. Se o ar da sala se tornar demasiado tóxico

E quando o Stinky Dog é morto, simplesmente reaparece na sua posição original.

Vamos torná-lo um pouco mais interessante: vamos acrescentar um som e uma animação.

A animação será uma lápide que surge do chão.

Vou criar um sprite de 4 frames para a lápide.

Primeiro desenhei a lápide completa; no Sprite Editor prime X para adicionar um novo sprite

Captura de ecrã do tutorial

A seguir, vou copiar e colar este frame 3 vezes, o que me dará quatro frames idênticos para este sprite. Para isso, uso as teclas:

M - copiar o frame

I - inserir um novo frame

K - colar o frame

I - inserir outro frame

K - colar o frame nele

I - inserir o último frame

K - colar o frame nele

Agora temos um sprite de 4 frames com a lápide completa em cada um.

Para isso podes usar as teclas D e F para percorrer os frames (D para trás, F para a frente)

Para dar o efeito de a lápide surgir do chão, vou precisar de a deslocar para cima 4 píxeis de cada vez (4 x 4 = 16, o nosso sprite tem 16 píxeis de altura)

Certifica-te de que estás a ver o Frame 000 (usa D ou F para chegar a ele, se não estiveres)

Agora prime o cursor PARA CIMA quatro vezes

Captura de ecrã do tutorial

O teu sprite deve agora ficar assim: o que eram as 4 linhas de cima são agora as quatro linhas de baixo.

Agora clica com o botão direito nos píxeis coloridos das 12 linhas de cima para os apagar. O teu Frame 0 deve ficar assim:

Captura de ecrã do tutorial

Quando estiver assim, prime F para passar ao frame seguinte.

Desta vez temos de o deslocar 8 píxeis para cima: prime a tecla para cima 8 vezes e depois apaga as 8 linhas de cima. O Frame 1 deve ficar assim:

Captura de ecrã do tutorial

Quando estiver assim, prime F para passar ao frame seguinte.

Desta vez prime o cursor PARA CIMA 12 vezes (ou o cursor para baixo 4 vezes) e apaga as 4 linhas de cima. Deve ficar assim:

Captura de ecrã do tutorial

Prime F para ir ao último frame. Deve mostrar a lápide completa, que é o que queremos, por isso não é preciso editá-lo.

Prime F outra vez e deves voltar ao Frame 0. Se criaste frames adicionais por engano, podes premir R para os remover.

Mantém o dedo em F e deves ver a animação na pré-visualização. Vai ser bastante rápida, mas não te preocupes, podemos controlar a velocidade no nosso código.

Agora que temos um sprite de lápide, vamos escrever código para ele. Vou colocá-lo em SPRITE TYPE 8; no teu menu Events seleciona Sprite Type 8.

Aqui está o código:

EVENT SPRITETYPE8

IF IMAGE 7           ; is it the tombstone
   FALL              ; make it subject to gravity
   IF FRAME <> 3     ; if we are not on the last frame
      ANIMATE MEDIUM ; animate the tombstone
   ELSE
      LET RND = 5    ; use RND as a temporary variable staring value of 5
      REPEAT 20      ; do the following 20 times
      BEEP RND       ; make sound based on current RND
      DELAY 2        ; a very brief pause
      ADD 5 TO RND   ; increase the BEEP value by 5
      ENDREPEAT 
      KILL           ; kill the player
      EXIT           ; stop processing this event
   ENDIF	
ENDIF

Primeiro, envolvi tudo numa instrução IF IMAGE 7. Fi-lo porque é provável que venha a usar o Type 8 para outros sprites não relacionados no futuro; assim, este código só será executado para o sprite da lápide.

Depois sujeitei-o à gravidade para que caia (FALL) até aos blocos de baixo, para não acabarmos com lápides suspensas no ar!

A seguir testo se NÃO estamos a mostrar o último sprite. IF FRAME <> 3 significa Se NÃO é o Frame 3.

E se não estamos a mostrar o Frame 3, quero que o frame seja ANIMADO (ou seja, percorra os frames) a velocidade MEDIUM.

ANIMATE aceita os argumentos:

Depois tenho um ELSE, ou seja, o que deve acontecer quando chegámos ao FRAME 3. Isto reproduz um som. Repara que, mais uma vez, estou a usar RND como variável temporária para controlar o efeito sonoro.

Depois de o som tocar, vamos matar o jogador com KILL, o que ativará a rotina KILL PLAYER.

Por fim, acrescentei um comando EXIT, que diz ao MPAGD para parar de processar este evento. Pode ser que não precisemos dele, mas costumo pô-lo quando é provável que venha a haver mais código neste evento que não quero que seja executado se o jogador já tiver morrido.

A seguir, vamos precisar de atualizar o nosso PLAYER EVENT para podermos ativar a lápide quando o Stinky Dog for morto. Abre o teu evento do jogador e procura a instrução IF DEADLY, que controla o que acontece quando o Stinky Dog toca num bloco mortal como os picos do nosso jogo. Provavelmente tem este aspeto:

IF DEADLY
   KILL
ENDIF

Vamos mudá-lo para isto:

IF DEADLY            ; am I touching something deadly?
   LET IMAGE = 7     ; if so, turn me into the tombstone sprite   
   LET FRAME = 0     ; reset me to frame 0
   LET TYPE = 8      ; make me a type 8 sprite
   EXIT              ; stop processing this event
ENDIF

Assim, quando o Stinky Dog tocar num pico mortal, vamos mudar a imagem do seu sprite para 7 (a lápide). Vamos também transformá-lo em TYPE 8 para que, a partir de agora, o código do evento TYPE 8 controle a lápide.

Repara que também quero garantir que, da primeira vez que executarmos o código do TYPE 8, o fazemos a partir do FRAME 0. Quando fazes um TYPE SWITCH a um sprite, todas as variáveis do sprite original, incluindo o número do FRAME, passam para o novo sprite. Como não podemos ter a certeza de em que frame o Stinky Dog estava quando toca num bloco mortal, queremos garantir que a lápide começa a partir do seu primeiro frame (FRAME 0).

Ok, vamos compilá-lo e testá-lo:

Funciona! Quando o Stinky Dog toca num bloco mortal aparece a lápide e ele morre.

Mas não acontece quando ele é morto pelo Sideways Clive, nem acontecerá se o medidor de pureza do ar chegar a 0. Porque até agora só mudámos o tipo de sprite no código IF DEADLY.

Por isso poderíamos acrescentar o mesmo código no código de COLLISION que deteta quando o Sideways Clive toca no Stinky Dog, e no código que mata o Stinky Dog quando a pureza do ar chega a 0.

Isso é muito código repetido e, à medida que o jogo se desenvolver, é provável que acrescentemos novas formas de matar o Stinky Dog. Seria melhor escrever uma rotina que possamos ativar sempre que quisermos matar o cão. O evento KILL PLAYER não é o melhor para isto, porque na verdade queremos controlar o que acontece JUSTO ANTES de matarmos o jogador no código.

É melhor, então, mantê-lo no PLAYER EVENT.

E para isso vamos usar uma das variáveis especiais de sprite para o ativar.

Vou usar SETTINGA como variável; é uma variável LOCAL, ou seja, é única para cada SPRITE. No Player Event, adiciona o seguinte código:

IF SETTINGA = 99     ; do we want to kill Stinky Dog
   LET IMAGE = 7     ; if so, turn me into the tombstone sprite   
   LET FRAME = 0     ; reset me to frame 0
   LET TYPE = 8      ; make me a type 8 sprite
ENDIF

Assim, agora, sempre que quisermos matar o cão, só temos de fazer LET SETTINGA = 99

Agora podemos atualizar o código mortal para:

IF DEADLY                ; am I touching something deadly?
   LET SETTINGA = 99     ; run the kill code
ENDIF

E o teste da pureza do ar para:

IF P <= 0             ; if air purity is 0
   LET SETTINGA = 99  ; run the kill code
ENDIF

Ok, isto serve para o que testamos no PLAYER EVENT, mas e a deteção de colisão com o Sideways Clive? Porque esse código está no evento do Clive (Sprite Event 1) e neste momento tem este aspeto:

IF COLLISION PLAYER        ; if Clive touches Stinky Dog
   IF DIRECTION <> 5       ; and if Clive is not stunned
      KILL                 ; Kill Stinky Dog
   ENDIF
ENDIF

Como SETTINGA é local do Stinky Dog, não podemos simplesmente substituir o comando KILL por LET SETTINGA = 99 no código acima, uma vez que isso alteraria, na prática, o valor SETTINGA do Sideways Clive para 99. Felizmente, o MPAGD tem uma solução: OTHER...ENDSPRITE.

IF COLLISION PLAYER        ; if Clive touches Stinky Dog
   IF DIRECTION <> 5       ; and if Clive is not stunned
      OTHER                ; switch to Stinky Dog
      LET SETTINGA = 99    ; run the death code
      ENDSPRITE            ; switch back to Sideways Clive
   ENDIF
ENDIF

OTHER só pode ser usado dentro de uma instrução IF COLLISION. Permite-nos mudar para o OUTRO sprite com o qual o sprite atual (neste caso o Clive) está a colidir. Temos sempre de voltar ao sprite atual com o comando ENDSPRITE.

Muito bem, vamos testar!

Nada mau: agora aparece a lápide quando o Stinky Dog toca num bloco DEADLY ou no Clive, e se a pureza do ar chegar a 0.

O único problema que vejo é que o Clive continua a andar por cima da lápide, por isso os gráficos sobrepõem-se e fica um pouco desarrumado.

Vamos ver como podemos melhorar isso.

Vamos acrescentar código no Type 1 (Clive):

IF COLLISION 8     ; if we touch a type 8 (tombstone)
   UNDOSPRITEMOVE  ; move clive off the tombstone
ENDIF 

O que isto deve fazer é que, se o Clive colidir com um sprite TYPE 8 (como a lápide), UNDOSPRITEMOVE desfaz o movimento que causou a colisão e, na prática, afasta-o da lápide.

Vamos testar outra vez!

Por agora está ótimo!

Todo o MPAGD Iniciantes