Pong com Slick2D em Java

Neste artigo, vamos aprender a utilizar uma simples biblioteca para jogos 2D chamada Slick2D. Esta biblioteca é bastante simples de usar e abstrai o programador das partes mais aborrecidas na implementação básica de um jogo, tais como a implementação do ciclo principal de jogo e comunicação com o sistema operativo.

Vou explicar o código da minha implementação, assim como os conceitos fundamentais no desenvolvimento de qualquer jogo. Para começar vamos estudar a estrutura fundamental de qualquer aplicação interactiva.

Um jogo, num nível mais abstracto, é uma aplicação que recebe e responde a eventos. Esses eventos podem ser externos (teclas pressionadas, movimento do rato) ou internos (por exemplo num jogo de carros, detectar a colisão contra uma parede). Em termos de código, isto traduz-se em algo semelhante a:

bool gameIsRunning = true;

while( gameIsRunning ) {
    update(); 

    render();
    if( userWantsToQuit() )
        gameIsRunning = false;
}

Enquanto a variável que indica se o jogo está a decorrer (gameIsRunning) o ciclo while é sempre executado. Em cada ciclo, actualizamos o estado do jogo e desenhamos o mundo para ecrã. Se o utilizador entretanto fechar a janela ou carregar numa tecla pré-definida para o efeito, a função userWantsToQuit retorna verdadeiro, actualizamos a variável de saída, e o ciclo acaba.

É fundamental que percebam este conceito, pois é a base de qualquer jogo. Numa aplicação mais complexa, existem mais pormenores a ter em atenção, mas para este jogo, a biblioteca abstrai grande parte do essencial.

Para começar, vamos criar um novo ficheiro em Java, importar a biblioteca Slick. Podem obter a biblioteca no site oficial localizado em http://slick.cokeandcode.com/. Eu vou utilizar a biblioteca no ambiente NetBeans IDE, mas não devem ter problemas com qualquer outro ambiente de desenvolvimento para Java.

Para dar uso da biblioteca Slick2D vamos criar uma classe para representar o jogo. Eu, num momento de grande originalidade, chamei a classe Game. Temos também de definir alguns métodos na nossa classe, que serão chamados pela biblioteca nos momentos apropriados.

package mongo;

import org.newdawn.slick.*;

public class Game extends BasicGame {
    public Game(String title) {
        // Para implementar
    }

    public void init(GameContainer gc) {
        // Para implementar
    }

    public void update(GameContainer gc, int delta) { 
        // Para implementar
    }

    public void render(GameContainer gc, Graphics g) {
        // Para implementar
    }

    public static void main(String[] args) {
        // Para implementar
    }
}

A classe principal vai extender a classe BasicGame, disponibilizada pela biblioteca. Esta é a estrutura base para qualquer jogo desenvolvido com a biblioteca Slick2D. Agora temos de escrever o código para iniciar a biblioteca e começar o ciclo principal de jogo.

public static void main(String[] args) {
    AppGameContainer app = new AppGameContainer(new Game(title));
    app.setDisplayMode(width, height, fullscreen); 
    app.setTargetFrameRate(fpslimit); 
    app.start();
}

Este código cria uma nova instância da aplicação e passa a classe correspondente ao jogo no constructor. O título pretendido (que queremos que apareça na janela) é passado como argumento do constructor da classe do jogo. Depois iniciamos a janela com a largura e altura desejada, e escolhemos se a janela vai ocupar o ecrã todo. Para finalizar, executamos o método que vai iniciar o ciclo principal do jogo. Como podem ver no código, os valores foram definidos como variáveis estáticas da classe, para facilitar futuras alterações.

static int width = 640;
static int height = 480;
static boolean fullscreen = false;

static String title = "Mongo";
static int fpslimit = 60;

Entretanto já temos definida a estrutura básica de uma aplicação, e se executarem a aplicação deve ser mostrada uma janela sem conteúdo. Para mostrar o conteúdo temos de implementar os métodos correspondentes ao ciclo de actualização e desenho da aplicação.

Vamos então pensar como modelar o jogo do Pong. Este jogo foi um dos primeiros video jogos e consiste numa simulação de um campo (de ténis de mesa), onde uma bola é atirada de um lado para o outro. O jogo é normalmente jogado por 2 jogadores, mas a nossa versão vai também ter uma opção onde o segundo oponente é controlado pelo computador.

Para representar as duas raquetes, podemos utilizar imagens, mas para facilitar a implementação vamos utilizar dois rectângulos. Para a bola, vamos utilizar um círculo. A biblioteca Slick2D já disponibiliza estas primitivas geométricas.

Circle ball;
Rectangle paddlePlayer;

Rectangle paddleCPU;

Para mover a bola pelo ecrã, temos de representar a sua velocidade. Estas quantidades são normalmente representadas por vectores de duas dimensões. A biblioteca Slick2D possui também uma biblioteca de matemática com estas primitivas implementadas. Vamos definir algumas variáveis para a velocidade e para armazenar as pontuações obtidas por cada jogador.

Vector2f ballVelocity;

int scorePlayer;
int scoreCPU;

Publicado na edição 25 (PDF) da Revista PROGRAMAR.