Trabalho pt.1: Porte de um jogo clássico


Apresentação

O jogo que escolhi foi o Green  House, lançado para Nintendo Game & Watch Multi Screen em 1982. Ele tem outras duas versões laçadas em coletâneas de jogos clássicos da Nintendo, uma de 1999 para Game Boy Color chamada Game & Watch Gallery 3 e outra de 2006 para Nintendo DS, chamada Game & Watch Collection. O jogo se passa em uma estufa e o personagem controlado pelo jogador tem que defender suas flores de insetos que tentam come-las. Ele faz isso do jeito mais ecologicamente errado possível: jogando veneno nos insetos! A cada inseto morto o jogador ganha de 1 a 3 pontos, e o jogo acaba quando se consegue 999 pontos ou quando 3 flores são mortas por qualquer um dos insetos que surgem na tela. Um vídeo mostrando a jogabilidade e algumas mecânicas do jogo pode ser visto neste link: https://www.youtube.com/watch?v=ydg9qci82OE

Modelos Naturais

Jogador
  • Pode se estar em 10 posições diferentes pela estufa, que é dividida em dois andares.
  • Só pode se mover horizontalmente em cada andar da estufa.
  • Pode viajar entre os andares da estufa se movendo verticalmente através de uma escada no centro da estufa.
  • Pode borrifar veneno para matar instantaneamente uma Minhoca
  • Pode borrifar veneno para matar instantaneamente uma Aranha muito próxima da flor ou afastá-la se ela estiver a uma distância de mais de uma posição da flor.


Flores
  • Ficam paradas nos cantos da estufa.
  • Quando mortas pelos insetos (Minhocas ou Aranhas) elas murcham e depois renascem.



Minhocas
  • Surgem na parte central do topo da estufa e caminham em direção a uma das flores do andar de cima.
  • Podem estar em 5 posições diferentes na tela, do centro até um dos cantos.
  • Quando uma delas come um flores, todos os insetos desaparecem.
  • Pode ser morta pelo veneno borrifado pelo jogador.
  • Quanto mais perto da flor, mais pontos ela rende ao jogador ao ser morta pela Fumaça, variando de 1 a 3 pontos.


Aranhas
  • Surgem no canto superior do andar de baixo da estufa e se movem para baixo na direção de uma das flores do andar de baixo.
  • Podem estar em 5 posições diferentes na tela, entre o canto superior do andar de baixo da estufa até a flores .
  • Quando uma delas come uma flor, todos os insetos desaparecem.
  • Pode ser morta pelo veneno borrifado pelo jogador se estiver perto da flor.
  • Pode ser repelida pelo veneno borrifado pelo jogador se estiver a uma distância de mais de uma posição da flor.
  • Quando repelida, rende 1 ponto ao jogador
  • Quando está muito próxima da flor, pode ser morta imediatamente pela Fumaça, rendendo 3 pontos ao jogador.


Fumaça 
  • Pode matar uma Minhoca quando borrifada pelo jogador no andar de cima da estufa.
  • Pode matar ou repelir uma Aranha quando borrifada no andar de baixo da estufa.
  • Pode estar em uma unica posição quando borrifada no andar de cima da estufa.
  • Pode estar em 5 posições diferentes quando borrifada no andar de baixo da estufa.
  • Pode ser borrifada pelo jogador em 6 posições diferentes da estufa.
  • Quando atinge um inseto é dispersada imediatamente.



Sistema 
  • Conforme a pontuação aumenta os insetos aparecer a uma frequência maior e ficam mais rápidos.
  • A cada flor morta por um inseto o surge na tela uma marca de falha.
  • A cada inseto morto pelo jogador um, dois ou três pontos são acrecidos ao placar.
  • Quando o jogador recebe 3 marcas de falha o jogo acaba.
  • Quando o jogador atinge 300 pontos todas as marcas de falha são retiradas.
  • Quando o jogador atinge 999 pontos o jogo acaba.
  • O jogador pode mudar entre o Jogo A e o Jogo B, que é mais rápido e difícil que o anterior (apenas o Joga A foi implementado neste porte).
  • Cria insetos em 4 posições diferentes da Estufa.



Modelos Matemáticos

Jogador

  • O jogador pode alternar entre 10 estados diferentes de movimento através das teclas direcionais do teclado.
  • Cada estado exibe um sprite diferente.
  • Cada estado só pode mudar para 1, 2 ou 3 outros estados possíveis, que correspondem às posições adjacentes do personagem no modelo natural.
  • Em 6 dos estados de movimento do personagem é permitido que ele altere para outros estados através da barra de espaço do teclado, que serão chamados de estados borrifando.
  • Em cada estado borrifando um objeto Fumaça diferente é criado antes que o personagem retorne ao estado anterior de movimento.
  • O jogador não consegue dar inputs quando está em um dos estados borrifando.





Flores
  • A flor pode alternar entre 2 estados diferentes: viva ou morta.
  • Cada estado exibe um sprite diferente.
  • O estado inicial da flor é viva e quando um inseto chega nela, ela muda seu estado para morta, e uma marca de falha é mostrada na tela.



Minhocas
  • Cada Minhoca pode alternar de maneira crescente entre 5 estados diferentes de movimentação.
  • Cada Minhoca pode alternar entre mais dois estados diferentes independente do estado de movimentação: viva ou morta.
  • Cada estado exibe um sprite diferente, que vai ficando, em ordem crescente do seu estado atual, cada vez mais perto da flor do ponto de vista do modelo natural.
  • Se seu estado coincidir com a existência de determinado objeto Fumaça no jogo, ela pode ser destruída.
  • Quando no estado 0, a Minhoca não pode ser destruída.
  • Quando nos estados de movimentação 1 e 2, a Minhoca só pode ser destruída com a Fumaça correspondente ao meio-esquerdo ou meio-direto da tela, dependendo também de qual Minhoca está fazendo o teste, se é a Minhoca da esquerda ou da direita.
  • Quando nos estados de movimentação 3 ou 4, a Minhoca só pode ser destruída com a Fumaça correspondente ao canto-esquerdo ou canto-direto da tela, dependendo também de qual Minhoca está fazendo o teste, se é a Minhoca da esquerda ou da direita.
  • Quando morta nos estados de movimentação 1 e 2, a Minhoca dá 1 ponto ao jogador.
  • Quando morta no estado de movimentação 3, a Minhoca dá 2 pontos ao jogador.
  • Quando morta no estado de movimentação 4, a Minhoca dá 3 pontos ao jogador.



Aranhas
  • Cada Aranha pode alternar de maneira crescente entre 5 estados diferentes de movimentação.
  • Cada Aranha pode alternar entre mais dois estados diferentes independente do estado de movimentação: viva ou morta.
  • Cada estado exibe um sprite diferente, que vai ficando, em ordem crescente do seu estado atual, cada vez mais perto da flor do ponto de vista do modelo natural.
  • Se seu estado coincidir com a existência de determinado objeto Fumaça no jogo, ela pode ser destruída.
  • Quando no estado 0, a Aranha pode ser destruída pela Fumaça, rendendo 1 ponto ao jogador.
  • Quando nos estados de movimentação 12, ou 3 a Aranha pode ser repelida pela Fumaça correspondente ao canto-esquerda ou canto-direta da tela, dependendo também de qual Aranha está fazendo o teste, se é a Aranha da esquerda ou da direita.
  • Quando repelida pelida pela Fumaça, a Aranha volta decresce 1 estado de movimentação.
  • Quando no estado de movimentação 4, a Aranha pode ser morta pela  Fumaça ao invés de repelida, dando 3 pontos ao jogador.



Fumaça
  • 6 Fumaças diferentes que podem ser criadas pelo jogador em posições específicas, 4 na tela superior e duas na tela inferior.
  • As Fumaças da tela superior tem 1 estado de movimentação apenas, e são destruídos depois logo depois de criadas.
  • As Fumaças da tela inferior tem 5 estados de movimentação, que se aproximam da Aranha correspondente a cada lado da tela de acordo com o modelo natural definido.
  • Cada fumaça da tela inferior começa no estado 4 e decresce até o 0, quando é destruída ou até encontrar com uma Aranha em um estado de movimentação comum (Os estados da Aranha acrescem do 0 até o 4).
  • Quando está em um estado de movimentação igual ao da Aranha, a Fumaça a repele, fazendo com que a Aranha retroceda um estado de movimentação e então a Fumaça é destruída.



Sistema
  • Checa a quantidade de falha do jogador. Se for igual a 3, o jogo atinge a condição de derrota e em seguida reinicia.
  • Checa a quantidade de pontos obtidos pelo jogador. Se chegar a 300, retira todas as marcas de falha acumuladas, e se chegar a 999 o jogo atinge a condição de vitória e em seguida reinicia.
  • Muda o placa do jogo exibindo na tela a quantidade de pontos obtida pelo jogador.
  • Cria insetos na tela de acordo com um valor randômico de uma variável local.
  • As Minhocas criadas não se repetem no evento de alarme seguinte, fazendo com que uma Minhoca do lado oposto seja criada em seu luga, ou seja, duas Minhocas que seguem na mesma direção não são criadas uma atrás da outra em sequência.
  • As Aranhas criadas não se repetem até que a instancia de Aranha que já está no jogo seja destruída (perceba que podem haver duas Aranhas diferentes em jogo, uma para cada lado da tela).
  • Quando o jogador chega às pontuações 100, 200, 400, 600 e 800, o valor base para o calculo de velocidade dos eventos baseados em tempo no jogo diminui, deixando a criação de insetos e mudanças de estado de todos os elementos em tela mais rápida.

Modelos Computacionais

Os códigos do porte podem ser obtidos no projeto do jogo (link mais abaixo), mas a priori podemos discutir alguns modelos mais gerais:

Todos os sprites dos objetos na tela são desenhados de forma sobreposta e sua interação é feita através de MEFs (Máquinas de Estados Finitos). Mas cada objeto pode surgir em duas posições distintas em Y, uma para cada tela (note que elas não são "coladas" uma na outra, havendo um espaço que meus sprites não previram).

Nem todos os objetos interagem entre com os demais, e existe uma série de variáveis globais usadas para definir alguns parâmetros, como vitória e derrota, a própria posição em X e Y onde os sprites são exibidos, e a quantidade de pontos obtidos pelo jogador a cada inseto morto, que varia de 1 a 3.

Todos os estados de movimentação dos insetos e Fumaças são compartilhado através de CONSTANTES do Game Maker, sendo que alguns objetos só sé aproveitam de um desses estados.

Todos os eventos de alarme do jogo são chamados em um tempo calculado com base em uma variável global que determina um valor padrão para ser multiplicado nas chamadas de eventos de alarme que envolvem tempo. Essa variável pode ser alterada de acordo com a necessidade.

O conceito de Objeto Deus, que checa a interação entre as várias MEFs é usado aqui como um objeto controle, mas muitas das checagens são feitas dentro dos próprios objetos insetos e Fumaças. Por exemplo, foi menos dispendioso do ponto de vista do código organizar o meu projeto de modo que o objeto Fumaça mudasse estados dos objetos insetos e em dado momento fosse capaz de destruí-los também. Isso me poupou tempo escrevendo o código e também evitou que todas as checagens importantes dependesse de uma única MEF, dando mais autonomia aos objetos e dividindo as etapas de debugagem em partes. Embora tenha funcionado bem pra mim, em termos de organização do projeto eu tenho minhas dúvidas se essa é uma prática eficiente.

Desenvolvimento do jogo

O porte do jogo foi desenvolvido no Game Maker 1.4, se aproveitando de ferramentas que facilitam a criação de sprites, eventos de alarme e algumas funções para imagens de background no projeto. Outras ferramentas usadas foram o Aseprite (editor de imagens e animações voltado para pixel art) para recorte dos sprites capturados de uma versão para Nintendo DS do jogo, o Photoshop para recorte e redimensionamento de algumas imagens de apoio, o DaVinci Resolve para edição de alguns sons do jogo e o emulador DeSmuME, para captura de sprites e estudo de referência de uma versão remasterizada do jogo clássico.

Para capturar os sprites do jogo, utilizei um emulador com uma Rom de um porte do Green House. Eu tirei um print geral com todos os sprites em tela e depois separei e salvei cada frame de cada personagem e elemento em uma imagem diferente.


Todos os sprites do jogo foram criados nas mesmas dimensões das duas telas somadas, logo, são todos chamados nas mesmas posições X e Y ficando sobrepostos. O que dá a impressão de movimento é que em cada frame da animação o desenho do sprite é deslocado dentro da imagem, mas todos tem o mesmo tamanho e não mudam de lugar.

As Aranhas e Minhocas que aparecem nos cantos da tela são espelhadas para o outro lado, aproveitam a mesma estrutura de código, alterando apenas as variáveis de sprites e com qual objeto eles interagem, no caso a Fumaça e a Flor, que por sua vez também quem suas contra-partes invertidas. Por exemplo, a Aranha do lado esquerdo (aranhaEsquerda) só interage com a Fumaça do lado esquerdo (fumacaBaixoEsquerda) e a Aranha do lado direito (aranhaDireita) só interage com a Fumaça do lado direito (fumacaBaixoDireita), e assim por diante para todos os objetos espelhados.


A interação na tela de baixo se dá quando há uma concomitância de estados entre os elementos. A Aranha vai do estado 0 até o 4, e a Fumaça vai do 4 até o 0, fazendo a "rota" contrária. Se a Fumaça estiver no mesmo estado que a Aranha, elas interagem entre si.

Todas as outras interações seguem uma lógica parecida. Se elemento A estiver em um estado X e elemento B estiver em um estado Y, eles podem ou não interagir. Se hover interação ela pode ser destruir o outro objeto e a si mesmo depois, ganhar pontos, tocar um som específico e assim por diante.

No caso das interações com pontos e marcas de falha, elas acontece quando as variáveis miss e pontos atingem um certo valor. Isso também acontece quando o objeto controle, que seria a MEF Deus, escolhe qual inseto vai aparecer de cada vez. Há uma variável que sorteia um numero de 1 a 10, que é checado por uma serie de condicionais. Seis desses números fazem surgir uma Minhoca no lado direito ou esquerdo, e outros quatro fazem surgir as Aranhas no lado esquerdo ou direito.

Além disso para definir qual sprite deve ser exibido, cada objeto checa seu próprio estado, de 0 a N, e atribui à variável interna responsável por mostrar os sprites na tela o mesmo valor do estado atual daquele objeto. Por exemplo, o sprite 0 da Aranha, mostra ela no topo da tela, o segundo mostra ela um pouco mais embaixo, e assim por diante, logo, se o estado da Aranha for 2, o sprite exibido será o número 2, que a exibe bem no meio do caminho até a flor, e assim até que a Aranha chegue no estado 5, onde ela deverá comer a flor e desaparecer em seguida. Todos os insetos no jogo seguem essa mesma lógica.

A parte da marca de falha foi um pouco mais complexa. Quando uma Flor morre, a tela congela por um segundo, então a MEF que checa as falhas desabilita o objeto Jogador, pra o jogador não poder controlá-lo, destrói todos os insetos na tela, diminui o Frame Rate do jogo para 1 FPS, e em seguida chama um alarme que habilita novamente o jogador e restaura o valor do Frame Rate para o valor padrão, que no meu caso é de 60 FPS. Essa foi uma maneira um tanto "gambiarrenta" de congelar a tela quando uma marca de falha é recebida, mas dessa forma eu não precisei adicionar outro estado a cada objeto do jogo, para mante-los parados na tela ou que modificasse o tempo de criação e mudança de estados dos insetos, por exemplo. Dessa forma eu poupei bastante tempo com as máquinas de estado.



Com toda a parte visual do jogo funcionando, a próxima etapa foi adicionar os sons. Eu usei os sons do jogo Donkey Kong II, também lançado para Nintendo Game & Watch Multi Screen. como todas as máquinas de estado estava funcionando visualmente, a única modificação no código foi adiciona a chamada de sons específica no momento antes dos objetos mudassem de estado ou fossem destruídos.

Alguns dos sons baixados foram modificados posteriormente para se adequar melhor às mecânicas do nosso porte, no caso, foram os sons que indicam quantos pontos o jogador ganha por vez, 1, 2 ou 3, dependendo da distância do inseto para a Flor, quanto mais próximo da Flor o inseto é morto, mais pontos o jogador ganha.

A última etapa foi adicionar uma imagem em volta das tela para simular o console físico. Também usei uma imagem do jogo Donkey Kong II para isso. Agora a posição em X e Y dos elementos precisou ser alterada, e para isso eu criei variáveis que armazenassem esses novos valores, descontando a posição, na imagem do console, para onde a tela deveria aparecer. As variáveis fora X e Y, simplesmente, que armazenavam os valores 150 e 69 respectivamente.



Aqui uma coisa interessante é que todos os elementos da tela de baixo precisaram ser deslocados mais ainda no eixo Y, já que originalmente as duas telas do console não são coladas uma na outra. Então para cada sprite exibido na tela de baixo o posicionamento em y agora era definido pela variável YY, que recebeu o valor de 432.

E além disso depois suas cores e alguns elementos foram editados para a imagem parecer com o console do jogo Green House, já que originalmente ela era do jogo Donkey Kong II.



Link do jogo e instruções

Para acessar o jogo e os arquivos do projeto, basta acessar o link abaixo:
https://drive.google.com/drive/folders/1lpeI4PpP5dhkQbo0W12bZqkRaJ9aIQus?usp=sharing
Instruções:
  • Aperte as setas direcionais para mover o personagem pelas telas.
  • Aperte a barra de espaço para borrifar veneno.


Referências:

Informações gerais sobre o jogo:
Intheattic - http://www.intheattic.co.uk/greenhouse.htm
Mariowiki - https://www.mariowiki.com/Greenhouse

Sprites: Foram retirados da versão de Nintendo DS (Game & Watch Collection), através do emulador DeSmuME. Posteriormente foram editados.
Emulador de Nintendo DS: https://wowroms.com/en/emulators-software/284/DeSmuME.html
Rom do jogo: https://wowroms.com/en/roms/nintendo-ds/game-and-watch-collection/16653.html

Sons: Foram extraídos de um porte do jogo Donkey Kong II (Nintendo, Game & Watch Multi Screen): http://www.madrigaldesign.it/sim/download.php

Imagem do console: Também foi extraída de um porte do jogo Donkey Kong II (Nintendo, Game & Watch Multi Screen): http://www.madrigaldesign.it/sim/download.php.



Comentários

Postagens mais visitadas deste blog

Tarefa da aula 09: Pong para um jogador - keyPressed e keyPressed()

Tarefa da aula 12: Jogo simples com MEFs