Ir para o conteúdo

Pong

Neste artigo, vamos aprender a utilizar uma simples biblioteca para jogos 2D chamada Slick. 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 varíavel 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 saida, e o ciclo acaba.

É fundamental que percebam esta 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.

Slick2D

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, mas não devem ter problemas com qualquer outro ambiente de desenvolvimento para Java.

Para dar uso da biblioteca Slick 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 Slick. Agora temos de escrever o código para inicializar 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 inicializamos a janela com a largura e algura desejada, e escolhemos se a janela vai ocupar o ecrã todo. Para finalizar, executamos o método que vai inicializar 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.

Pong (1972) - Atari Inc.

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 também de representar a sua velocidade. Estas quantidades são normalmente representadas por vectores a duas dimensões. A biblioteca Slick possui também uma biblioteca de matemática com estas primitivas implementadas. Vamos definir também variáveis para armazenar as pontuações obtidas por cada jogador.

    Vector2f ballVelocity;

    int scorePlayer;
    int scoreCPU;

Já temos então tudo o que precisamos para armazenar o estado de jogo. Agora temos de implementar os vários métodos que deixámos em branco na classe de jogo.

public void init(GameContainer gc) throws SlickException
{
    gc.getInput().enableKeyRepeat();

    paddlePlayer = new RoundedRectangle(5, height/2, 10, 80, 3);
    paddleCPU = new RoundedRectangle(width-15, height/2, 10, 80, 3);
    ball = new Circle(width/2, height/2, 6);
    ballVelocity = new Vector2f(-3, 1);
}

Recursos