Metal Gear Nanna – Criando jogos usando C++ e OpenGL: o modelo – Parte II

Diagrama de classes inicial
Diagrama de classes inicial

O mais importante no projeto deste jogo, sem sombra de dúvidas é o modelo, pois os gráficos, assim como toda a interação do usuário com o jogo é resultado do estado definido neste.

Vamos começar pela classe Elemento. Esta representa, como o próprio nome já diz, um objeto que será representado na janela principal do nosso jogo. Trata-se de uma classe abstrata, que irá prover os atributos e métodos básicos que serão utilizados pelos elementos concretos do nosso jogo: Nanna, Inimigo, Parede e Destino (os explicarei novamente a seguir).

Na classe Elemento os seguintes atributos encontram-se definidos:

x e y: a posição do elemento na tela. No caso, por padrão estes elementos irão corresponder ao canto superior esquerdo de cada elemento de tela.

altura e largura: adivinha! :)

visivel: indica se o elemento em questão será renderizado ou não pela aplicação. Este atributo só será de fato útil quando formos trabalhar com a inteligência do jogo.

Esboço de Nanna vista de frente

direcao: a direção do elemento naquele momento. É importante para que saibamos qual imagem renderizar. Por exemplo: se Nanna estiver na direção NORTE, iremos renderizá-la de costas, se for SUL, de frente

A classe abstrata Elemento possui dois métodos abstratos que são fundamentais para nosso jogo:

Elemento::draw(): Desenha o elemento na tela. Cada elemento irá se desenhar de maneira distinta. Por esta razão, este método foi definido como abstrato nesta classe, obrigando as demais a implementá-los.

Elemento::mover(direcao: tipoDirecao, incremento: float): Este método recebe dois parâmetros: direcao e incremento. O parâmetro direcao indica para onde estou movendo o elemento (veja o enum tipoDirecao no diagrama de classes para ver seus valores óbvios), e incremento a distância percorrida pelo elemento a cada chamada deste método. No caso, serão alterados os atributos x e y da classe, que correspondem à sua posição na tela.

Descrita a classe Elemento, vamos passar agora para a descrição das suas classes derivadas:

Metal Gear Nanna

Nanna: Trata-se de nossa heroina. No estágio inicial do código fonte, trata-se do único elemento que podemos movimentar (e que possui qualquer tipo de movimento, diga-se de passagem). Só para lembrar, o objetivo de Nanna consiste em evitar ao máximo os “Traficantes de Delícias” (classe Inimigo), que uma vez a avistando, irão obrigá-la a comer alguma coisa, reduzindo assim o número de pontos que obteve nos vigilantes do peso.

Estou prevendo para Nanna duas capacidades: a de se movimentar e também a de distrair os seus inimigos. Para tal, Nanna irá gritar, fazendo com que os mesmos mudem de direção, possibilitando assim que ela os despiste.

Esboço dos Inimigos de Frente
Esboço dos Inimigos de Frente

Inimigo: Ah, estas cozinheiras da Bahia… Vivem nos engordando!  Seu comportamento será definido pelo próprio mecanismo do jogo ao invés de Nanna, que será comandada pelo jogador.

No caso do Inimigo, há alguns atributos a mais: ele possui um raio de visão (definido pelo atributo direcao) e também se movimentará sozinho pelas 4 direções em busca de Nanna. Uma vez que esta esteja no seu campo de visão (que também será rendericado), automáticamente Nanna perderá pontos.

Esboço de uma parede
Esboço de uma parede

Parede: Uma paredde é uma parede, que é uma parede e, bem: uma parede. A única função de uma parede consiste em limitar os movimentos de Nanna. Uma parede não se move (ao menos não inicialmente), sendo assim, o método mover em nada modificará os atributos de uma parede neste momento.

O único método sobrescrito no caso será draw, que deverá expor o esboço exposto ao lado.

Destino: Para chegar ao final de uma fase, Nanna precisa saber aonde chegar. Por esta razão, existe a classe destino. No momento em que Nanna interceptar o destino, o mapa atual será descarregado da memória e o seguinte carregado, até que todos os mapas sejam finalizados e o usuário chegue ao final do jogo.

O Mapa!

O mapa pode ser visto como o container de todos os elementos do nosso jogo. Nele estarão armazenados os apontadores para cada classe derivada de Elemento de nossa aplicação.

Neste estágio atual do jogo, o código mais interessante sem sombra de dúvidas é o mapa, que inclusive já é renderizado (toscamente, é verdade, mas renderizado!), como pode ser visto na imagem abaixo:

Mapa atual de Metal Gear Nanna
Mapa atual de Metal Gear Nanna

Todos os elementos são inicialmente renderizados como quadrados, variando apenas suas cores: Nanna é vermelha, o Inimigo laranja, as paredes azuis e o destino verde (soa quase como um poema, não é mesmo?).

No caso, as posições dos elementos são definidas em arquivos externos, carregados pelo programa quando o mesmo é iniciado. Estes arquivos externos encontram-se no formato texto para que sejam de fácil edição, e são similares ao exposto na imagem abaixo:

Cada linha do arquivo possui um significado:

Primeira linha: nome do mapa

Segunda linha: código interno do mapa (será muito útil em um futuro próximo)

Terceira e quarta linnhas: número de linhas e colunas do mapa (mais sobre isto abaixo)

Linhas subsequentes:

As linhas subsequentes dizem respeito ao posicionamento dos elementos na tela. No caso, es trata de uma matriz de n linhas por m colunas, tal como definido nas linhas de número 3 e 4 do arquivo de configuração do mapa.

Cada caractere dentro desta matriz representa um dos elementos descritos acima: V = vazio, N = Nanna, I = Inimigo e E = Saída. Na realidade, para elementos vazios poderia ser definido qualquer caractere diferente de N, I ou E. No entanto, para que a visualização fique mais fácil, optei pelo caractere V mesmo (se quiser, modifique o arquivo de mapa trocando os caracteres V por qualquer coisa. Você verá que o programa funciona da mesma forma).

Conforme este arquivo é carregado, novas instâncias da classe Elemento vão sendo criadas e seu posicionamento configurado de acordo com a linha e coluna na qual se encontram (fica nítido no código fonte como isto é feito).

Renderização do mapa

A renderização do mapa é simples: neste há um atributo chamado conteudo, do tipo ItemLista. Este na realidade é o elemento inicial de uma linha encadeada. Sendo assim, o que o software realmente faz consiste em interar em cima destes elementos executando o método draw de cada instância. Em seguida, é chamado o método draw do atributo Nanna, que não se encontra dentro desta listagem.

Nanna não se encontra dentro desta listagem por duas razões:

1) É um elemento que é acessado constantemente

2) É um elemento único. Em um mapa, ao menos por enquanto, só pode haver uma Nanna.

O código fonte

Ei! Após ter falado tanto do programa, com certeza vocês devem estar querendo dar uma olhada no mesmo, certo? O disponibilizei para download neste link. Eu sei que é uma maneira bem tosca de disponibilizar código fonte, mas é que ainda estou procurando algum lugar para hospedar o meu repositório Mercurial. Assim que o encontrar liberarei para vocês maiores detalhes sobre como obter versões atualizadas deste bichinho.

(eu pensei no github, mas o estado do git para Windows (sim, estou usando Windows ao invés de Mac OS no desenvolvimento deste projetinho…) atualmente ainda é muito precário, além disto, devo confessar que tenho uma certa preferência pelo Mercurial)

Fontes adicionais de informação

Neste estudo, alguns livros estão sendo de EXTREMA valia para mim:

C++ Como Programar

O melhor livro de C++ que conheço, é o dos Deitel (assim como o livro de Java, Perl e C# também são os melhores).

Se você quer saber o básico de programação em C++, o livro é este.

OpenGL: Uma Abordagem Prática e Objetiva
De Marcelo Cohen

Um excelente texto introdutório ao OpenGL. Basicamente, do pouco que sei de OpenGL até agora, 90% vêm desta fonte.

A abordagem é muito simples, tornando o contato inicial com OpenGL pouquíssimo traumático. Na realidade, é até surpreendente: eu realmente achava que OpenGL fosse algo que só engenheiros da NASA pudessem dominar. Com este livro, vi que a história não é bem assim.

Computer Graphics: Theory Into Practice
De Jeffrey J. McConnell

Enquanto o OpenGL: Uma Abordagem Prática e Objetiva é mais mão na massa, o foco deste livro é mais a teoria por trás da computação gráfica. Aliás, primeiro tomei contato com este livro, e só depois com o primeiro.

Os exemplos do livro são todos em OpenGL, sendo assim, o que o primeiro não tratar, com certeza você encontrará com maiores detalhes neste.

Daqui para frente…

Se você executar o código fonte atual, irá perceber que Nanna pode fazer algo incrível: ela passa pelas paredes. Sendo assim, antes de renderizar Nanna com gráficos melhores, a primeira coisa a ser feita consiste em implementar os algoritmos de detecção de colisão.

Sendo assim, nos próximos posts começarei a trabalhar com maiores detalhes questões referentes à implementação de Metal Gear Nanna. Neste processo, iremos ver como funciona o OpenGL e também quais os erros que venho cometendo neste desenvolvimento (o que normalmente é o mais interessante em todo aprendizado).

Logo… até o final de semana que vêm (ou antes)!

4 Comments

Add Yours →

Interessante, teve uma vez que eu usei o mesmo conceito para criar um jogo do bomberman, mas só dava para jogar contra outro jogador, porque a parte da IA é mais dificil e é uma das áreas que chama mais minha atenção. Então, se algum dia você puder publicar código de IA, será bastante interessante.
Valeu pela informação!

Responda

Gostei desse seu post e me interessou bastante mas gostaria de saber se você não continuou este projeto. Ate +

abraços!

Responda

admin Reply:

Oi Victor, acabei não caminhando com ele devido a problemas completamente fora do meu controle :(

Responda

Eu testei seu código, percebi que não deu continuidade ao projeto, mas…

Você chegou a incluir algum algoritmo de buffer para a renderização? No caso ele suavizaria a animação….

Responda

Deixe um comentário

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.