Concrete Logo
Hamburger button

Como desenvolver seu próprio jogo – Parte 2

  • Blog
  • 14 de Março de 2014
Share

Ajustando perspectivas e movimentos

Este post faz parte de uma série sobre como desenvolver seu próprio jogo. O começo de tudo você pode aprender neste link. Se tudo deu certo, ao executar a nossa primeira versão do pong teremos uma imagem semelhante à que está abaixo:

jmonkey_parte2_1

Não é exatamente o que teríamos em mente para um jogo de pong, mas pelo menos é um começo. Vamos resolver isso agora, ajustando a perspectiva de câmera e o posicionamento dos nossos objetos.

No final do método “simpleInitApp()”, é só colocarmos as linhas:

Com essas pequenas mudanças, reposicionamos a câmera na nossa cena, e reposicionamos os jogadores da direita e da esquerda, afastando-os do centro da cena.

jmonkey_parte2_2

Estamos no caminho certo, mas já fizemos muitas coisas sem entrarmos nos detalhes de como elas aconteceram. Acho que é uma boa hora para vermos um pouco sobre a teoria do que fizemos, facilitando o entendimento dos próximos passos.

A nossa classe principal do jogo (que no momento é a que faz tudo), estende SimpleApplication. A SimpleApplication facilita o início do processo de desenvolvimento, pois já disponibiliza as estatísticas de cena, vistas nos screenshots no canto inferior esquerdo, além de adicionar uma câmera que se movimenta com as teclas W,A,S,D e mostrar o framerate atual.

Uma das características importantes do SimpleApplication é que ele disponibiliza alguns métodos que temos que sobrescrever para que nosso jogo funcione. Um deles nós utilizamos no exemplo, chamado simpleInitApp. Esse método é executado quando o framework está pronto para executar a aplicação. Nele montamos as nossas cenas e preparamos tudo que é necessário para renderizar e interagir com os objetos.

Além disso, o SimpleApplication disponibiliza algumas variáveis que facilitam muito a utilização inicial do jMonkey. A principal delas, que é utilizada no exemplo, é o rootNode. A organização da cena no jMonkey é baseado em uma estrutura hierárquica de Nodes. Cada Node herda algumas características do Node pai. Para o nosso exemplo no momento, é suficiente saber que qualquer Node que queiramos que apareça precisa ser filho direto ou indireto do rootNode.

jmonkey_parte2_4

Um exemplo de como está organizada a nossa cena pode ser visto na imagem ao lado. Note que temos todos os objetos posicionados diretamente como filhos do rootNode.

Uma excelente e simples explicação sobre essa estrutura está disponível em inglês neste link.

Agora que explicamos um pouco do que fizemos até o momento, vamos fazer um último ajuste nos nossos jogadores, e para finalizar essa parte, vamos adicionar um pouco de controle a eles.

Os mais observadores já perceberam que nossos jogadores encontram-se “deitados” em relação ao plano da câmera. Isso acontece por um lapso nosso durante o processo de criação dos jogadores. Para resolver é só alterar a ordem dos parâmetros dos construtores dos jogadores, deixando-os conforme o código a seguir:

Com isso feito, podemos agora adicionar as teclas que queremos para movimentar os nossos jogadores. Para começar, adicionamos o seguinte código no final do método simpleInitApp()

A última linha faz referência a um analogListener que ainda não foi definido. Então, vamos criá-lo como uma classe privada embutida na nossa classe de aplicação, conforme o código a seguir:

O sistema de controle do jMonkeyEngine conta com duas formas principais de receber a entrada dos jogadores: os listeners analógicos e os listeners de ação. Existem algumas sutis diferenças entre um e outro, e vamos analisá-las com mais detalhe na continuidade da série.

Nesse caso em particular, escolhemos o listener analógico, pois para teclas de teclado ele se comporta como um OnKeyDown de outras plataformas, ou seja, a cada frame podemos checar se a tecla está pressionada efetivamente.

No código que colocamos ao final do simpleInitApp(), damos nomes para as nossas ações (nesse caso, “ESQUERDA_CIMA” e “ESQUERDA_BAIXO”) e associamos essas ações com teclas específicas (no caso, teclas “R” e “F” respectivamente). E, na última linha, dizemos que a classe analogListener é a responsável por tratar essas ações. É interessante notar que após nomeadas, as ações serão sempre referidas por nome, tornando fácil o processo de reatribuir teclas durante a execução do jogo.

A implementação do analogListener é bem trivial. Precisamos apenas destacar duas informações que são passadas ao método. Uma informação, que não é utilizada no nosso exemplo, é o value. Ele é um float que varia entre 0 e 1 e serve para dar o valor de um eixo de um controle, por exemplo. No caso do nosso exemplo, ele seria sempre 1, então nós ignoramos este valor.

Outra informação importante é o tpf (time per frame) ou “tempo por frame”. Ele efetivamente mede quantos milisegundos se passaram entre a renderização de dois frames consecutivos. Quando escrevemos “_jogadorEsquerda.move(0, tpf * 5, 0);”, estamos dizendo para o objeto se deslocar 5 unidades por segundo na direção do eixo Y. Ou seja, quando multiplicamos o valor do deslocamento pelo tpf, o transformamos em uma constante em relação ao tempo. Se não fizéssemos a multiplicação, diríamos para fazer um deslocamento de 5 unidades por frame, e então se a máquina do nosso jogador fizesse 60 frames por segundo, ele se deslocaria 300 unidades. Se ele fizesse 15 frames por segundo, se deslocaria 75 unidades, o que torna o jogo imprevisível. Multiplicando pelo tpf, independente de quantos frames por segundo da máquina do jogador faça, a velocidade percebida de deslocamento será constante.

Como exercício, deixaremos por sua conta a implementação do código para mover o jogador da direita. Como dica, pode-se usar o próprio analogListener que já está criado para fazer esse controle. Cuidado só para deixar os dois players se moverem ao mesmo tempo.

O código disponível no repositório já estará permitindo que o jogador da direita se movimente, utilizando as teclas “I” e “K”.

Na próxima parte, vamos fazer a bola se deslocar e colidir com os nossos jogadores. Como sempre, o código está disponível no repositório: Parte dois. Caso tenha alguma dúvida ou alguma sugestão, basta deixar o seu comentário. Até a próxima!