Jogos em Java SE
Artigo Java Magazine 44

Introdução ao mundo de jogos em Java para desktop

A indústria de jogos eletrônicos mundial vem crescendo de forma intensa. Segundo dados da Juniper Research, o faturamento global deve passar dos 3 bilhões de dólares, em 2006, para mais de 17 bilhões, em 2011. Neste primeiro artigo de uma série, vamos mostrar na prática que Java é uma tecnologia excelente para desenvolvimento de jogos.

Antes de começarmos a criação do nosso primeiro jogo – o que ocorrerá na segunda parte – abordaremos conceitos iniciais sobre implementação de jogos em Java para desktop e apresentaremos algumas APIs.

Jogos eletrônicos em Java?

Jogos em Java? Essa pergunta ainda é comum em discussões entre programadores, que supõem, sem cerimônias, C e C++ como linguagens “default” nessa área. Argumentos? Sim, eles os têm. Vamos derrubar os principais.

Softwares em Java são muito lentos

Bom, quem disse isso estaria com a razão se estivesse bastante desatualizado, ou se estivesse nos anos 90, década em que o Java foi concebido e que as máquinas virtuais Java (JVMs) davam seus primeiros passos. Hoje, as JVMs são poderosas e seus otimizadores usam técnicas avançadas para obter performance igual ou superior à de código nativo.

Games em Java não têm poder comercial

A quantidade de jogos desenvolvidos em Java para desktop ainda é menor que em outras linguagens, exatamente pelo preconceito citado no argumento anterior. Mas os profissionais de criação de jogos vêm percebendo que estão errados em subestimar o Java. Na lista de links desse artigo, você encontrará alguns casos de sucesso significativos do uso de Java para a criação de jogos.

Java é alto nível

No início, quando o desenvolvimento de jogos em Assembly era comum, C aparecia como uma linguagem de altíssimo nível. E naquela época foram desenvolvidos jogos – em C – de sucesso incontestável, como o Doom da Id Software. Dessa forma, é inconcebível o argumento de que uma linguagem de alto nível não seja candidata ao desenvolvimento de jogos. A elevação do nível de abstração é benéfica e é uma tendência há vários anos.

Conceitos iniciais

Os projetos de jogos envolvem diversas áreas da computação e afins, tais como Inteligência Artificial, Engenharia de Software, Computação Gráfica, Estruturas de Dados, Lógica, Física, Geometria, entre outras. Dentro desse cenário, há a necessidade de discutirmos alguns conceitos iniciais.

Etapas do desenvolvimento de jogos

Podemos comparar a produção de um jogo à de um grande sistema de informações. O processo de desenvolvimento é similar em diversos aspectos, havendo por exemplo as atividades clássicas de definição do projeto, análise, implementação e testes. Porém, dada a natureza artística de um jogo, processos muito rígidos facilmente sofrerão rejeição por parte de engenheiros e gerentes da área de jogos. Desta forma, é comum adaptar processos de forma a torná-los mais flexíveis. Aqui descrevemos algumas etapas e atividades principais no desenvolvimento de jogos.

Especificação do jogo

A especificação descreve a idéia central e a sinopse do jogo. Além disso, são fornecidos detalhes em vários formatos, como storyboards das animações, mapas, comportamento dos “inimigos”, esquemas de bônus e fases, níveis de dificuldade, cenário (mundo), dentre outros.

Análise/Desenvolvimento de framework

Muitos dos jogos mais complexos são construídos sobre um framework, que define a arquitetura e o ciclo de vida do jogo a ser desenvolvido, entre outros recursos fundamentais. O uso desses frameworks traz o aumento de produtividade e de padronização. Caso a equipe de programação já possua um framework, esse é o momento para analisar se alguma correção ou melhoria deverá ser realizada e fazer a extensão e adaptação necessárias. Em muitos casos, a equipe não contará com um framework adequado para os jogos sendo desenvolvidos. Nesse caso, será necessário o desenvolvimento de um novo framework. O framework criado ou adaptado deverá passar por uma bateria de testes e ser validado com a criação de um jogo mais simples construído sobre ele.

Arte

Nesse momento entram em ação os profissionais responsáveis pela arte e efeitos visuais. Esses artistas utilizarão ferramentas de manipulação de imagens e modelagem tridimensional para concretizar as idéias na especificação do jogo. A equipe de arte precisa estar em contato constante com os desenvolvedores.

Implementação

Essa etapa envolve o desenvolvimento propriamente dito do jogo, sobre o framework criado ou adaptado. Em muitos casos, ela é dividida, de forma a se obter uma etapa de análise antes da de desenvolvimento, onde serão discutidos aspectos de estrutura de dados, inteligência artificial e mecânica do jogo, entre outros.

Som e Música

Nesta etapa, agrega-se ao projeto o profissional de música, o sonoplasta e outros especialistas em produção de sons, que tratarão dos recursos sonoros e musicais.

Usabilidade e testes

Os profissionais da usabilidade farão diversos testes com usuários de vários perfis (privilegiando o perfil do principal público-alvo). O objetivo é obter informações que ajudem a tornar o jogo mais intuitivo e com o maior apelo e jogabilidade possível. Além disso, claro, uma bateria de testes funcionais detalhados deve ser aplicada sobre o jogo.

Ciclo de vida

O ciclo de vida para jogos pode ser dividido em três macro-etapas (veja a Figura 1):

  • Checar controles – Verificar se há algum sinal vindo dos dispositivos de entrada, como o pressionamento das setas direcionais ou movimento do joystick, por exemplo.
  • Atualizar – Fazer a atualização do estado do jogo, de acordo com a interação do usuário. Aqui está toda a regra de negócio do jogo, por exemplo qual será a reação de uma personagem ao ser pressionada uma tecla de seta ou forem encontrados obstáculos.
  • Desenhar (ou renderizar) – Redesenhar a tela conforme o estado atual do jogo.
Enquanto o jogo estiver sendo executado, teremos um laço com essencialmente três etapas
Figura 1. Enquanto o jogo estiver sendo executado, teremos um laço com essencialmente três etapas.

Essas etapas são executadas em seqüência, apesar de o usuário ter a nítida impressão de que tudo acontece simultaneamente. Embora existam outras abordagens de ciclos de vida, a que exploraremos aqui envolve uma única thread que realiza as três etapas sequencialmente, conforme mostra a Listagem 1. Essa thread concorrerá com threads de carregamento, dentre outras que exploraremos nas partes seguintes.

Listagem 1. Trecho da thread do jogo.

//...

public void run() {

  executando = true;

  while (executando) {

    checarControle();

    atualizar();

    desenhar();

    ...

 

    try {

      Thread.sleep(40);

    }

    catch (InterruptedException ex) {

    }

  }

}

//...

Entre cada iteração do laço mostrado na listagem, há uma chamada a sleep(), ou seja, fazemos a thread parar sua execução por um tempo determinado. Isso é uma técnica simples para controlar a quantidade de quadros por segundo (FPS – frames per second) do jogo. Os quadros são como fotos, que se trocadas a certa velocidade mínima, parecem uma animação ao olho humano.

Note que existem outros modelos de execução, que derivam desse ciclo de vida e que são aceitos e bastante utilizados no mercado. O mais comum é uma variação que usa duas threads, uma para a checagem de controles e a atualização, e outra para a renderização (desenho).

Sprite

Sprites são coleções de imagens que representam vários estados de uma entidade gráfica. Esse recurso é comumente utilizado para criação de animações de personagens ou outros elementos animados. Um sprite é geralmente formado por diversos quadros posicionados lado em lado em uma única imagem. A troca desses quadros a certa velocidade causará sensação de animação. Os quadros do sprite são freqüentemente mapeados por índices, permitindo identificar e acessar cada quadro facilmente.

Sprite mapeada por matriz
Figura 2. Sprite mapeada por matriz.

Veja dois exemplos de sprites na Figura 2. Supondo que um determinado jogo possua dois perfis de personagens, podemos imaginar que a seqüência de frames 0, 1, 2, 3 representa a animação da personagem amarela, e a seqüência 4, 5, 6, 7 representa a segunda personagem.

Colisão

O conceito de colisão é fundamental no universo dos jogos. Há duas preocupações: detectar a colisão e reagir a essa colisão. Detectar a colisão é perceber o momento exato em que dois objetos se chocaram, ou em que um objeto entrou em contato com algum elemento do ambiente. Existem diversas soluções para detecção de colisões. Uma solução relativamente simples é circunscrever os objetos em questão, ou suas partes, dentro de formas geométricas primitivas, como uma esfera ou um cubo, ou uma circunferência ou retângulo em jogos 2D (veja a Figura 3).

Objetos mapeados por formas geométricas, para efeitos de detecção de colisão
Figura 3. Objetos mapeados por formas geométricas, para efeitos de detecção de colisão.

Considerando o caso ilustrado, se durante o jogo as circunferências da personagem tiverem interseções com as de outra personagem, podemos considerar que houve uma colisão.

A percepção de colisões por si só não teria utilidade se não reagíssemos a elas, é claro. Essa tarefa, em muitos casos, envolve cálculos bastante sofisticados, levando em consideração aspectos como velocidade, força, tolerância, aceleração, dentre outros.

O que tem pronto?

Existem diversas APIs prontos no mercado, com objetivo de abstrair complexidades como as envolvidas na renderização de animações, detecção de colisões e muitas outras funcionalidades comuns em jogos. A seguir apresentamos algumas.

  • LWJGL (Lightweight Java Game Library) – Oferece acesso a APIs de alta performance independentes de plataforma tais como o OpenGL e OpenAL, para criação de arte e sons, com enfoque na programação de jogos. Já existem diversos jogos desenvolvidos com a LWJGL; o Vermin Exerminator é um exemplo open source (www.vermin-exterminator.de/en). Veja uma lista de outros projetos relacionados em www.lwjgl.org/projects.php.
  • JOGL (Java Binding for the OpenGL API) – Biblioteca Java que fornece serviços gráficos 3D baseados em OpenGL para aplicações escritas em Java. jogl.dev.java.net.
  • JOAL (Java Bindings for OpenAL) – Engine Java de som que permite acesso fácil à OpenAL (biblioteca open source para a criação de sons 2D e 3D). joal.dev.java.net.
  • lib3ds – Biblioteca nativa útil para manipular arquivos .3ds gerados pelo 3D Studio Max. Há mapeamentos para Java. lib3ds.sourceforge.net.
  • audiere – Biblioteca open source de alto nível capaz de realizar operações de entrada e saída, decodificação e mixagem de áudio. audiere.sourceforge.

Conclusões

Esse artigo dá inicio a nossa jornada pelo desenvolvimento de jogos. No próximo, desenvolveremos um jogo simples utilizando algumas das APIs apresentadas aqui.