Projeto de MAC-211 -- 2009
Protetores do Espaço Sideral 2: A Missão

Fabio Kon - Marcelo Reis

Nos capítulos anteriores....

Inicia-se agora a segunda parte de nossa odisseia espacial!

Segunda Fase: Visualização Gráfica

Agora que a geração dos asteróides e dos cristais está funcionando, vamos apresentá-los em uma janela gráfica, no gerenciador de janelas de sua preferência (Gnome, KDE, Xwindows, etc.); ou seja, você deverá adaptar o código que escreveu na fase anterior para que o mesmo utilize elementos gráficos ao invés de usar caracteres em modo texto, na representação do espaço, das espaçonaves, dos cristais e dos asteróides. Além disso, você deve fazer a sua simulação ser executada em tempo real: ou seja, as naves, os asteróides e os cristais devem se movimentar na tela com o passar do tempo numa velocidade "razoável". Assim, 1 segundo simulado será bem próximo de 1 segundo do tempo real (aquele tempo que o seu relógio de pulso mostra). Você ainda não precisa se preocupar com o controle das espaçonaves nem com a interação com o usuário: esses aspectos serão desenvolvidos na próxima fase.

Cada asteróide ou cristal irá corresponder a um quadrado ou círculo na tela; se quiser, você pode usar formas irregulares para dar mais realismo ao formato dos objetos, mas é desejável que seu formato sempre se aproxime de um quadrado ou de um círculo. Não use um formato muito esdrúxulo pois isso dificultará a detecção de colisões.

O número de pixels que representam cada asteróide ou cristal na tela deve variar de acordo com a massa do objeto, mas deve sempre ser próximo ao valor D, que deve ser uma constante definida no programa (ou seja, objetos de tamanho "médio" são representados com D pixels, objetos "grandes" com mais de D pixels, e objetos "pequenos", com menos de D pixels). Inicialmente o valor de D será 10, mas poderá ser alterado em função da resolução e da velocidade do programa final. Fica a seu critério escolher valores para as constantes de forma a favorecer a "jogabilidade" do seu jogo.

Espaçonaves

"... to boldly go where no man has gone before."

As espaçonaves de Kirk e de Spock deverão ser representadas por triângulos isósceles, uma de cada cor; o tamanho das espaçonaves deve ser maior que o tamanho do maior dos asteróides e dos cristais, porém não muito maior, para não inviabilizar o jogo. Um dos lados do triângulo é a "traseira" da nave, onde encontra-se o jato propulsor; o vértice oposto a esse lado é que dispara o phaser que deve destruir os asteróides.

A implementação do phaser e do campo de força, assim como os controles das espaçonaves, ficarão para a próxima fase; por hora, vamos apenas simular a movimentaçao das naves pelo espaço sideral. A simulação será feita da seguinte forma:

Como em toda boa ficção científica, para fins dramáticos, uma pequena explosão deve ocorrer nas colisões envolvendo uma das naves e um asteróide. Aqui vale a sua criatividade para elaborar esse efeito! :-)

Bibliotecas Gráficas

Os desenhos e a animação serão feitos com base em uma das duas bibliotecas: xwc ou Allegro. A xwc nada mais é do que uma casca em cima da biblioteca básica do gerenciador de janelas, a libX11; ela é simples o suficiente para permitir facilmente a construção de extensões: assim, se a xwc não faz algo que você gostaria que ela fizesse, você pode estendê-la. Veja abaixo a seção xwc. Já a Allegro é uma biblioteca bastante abrangente, voltada para o desenvolvimento de jogos 2D em C/C++; a biblioteca não só conta com recursos gráficos, como também de som, gerenciamento de teclado, mouse e joysticks, etc. Veja abaixo a seção Allegro. Cada grupo deve escolher uma dessas duas bibliotecas para a implementação desta fase.

Lembretes




xwc

Esta seção apresenta um pequeno resumo das funções do xwc. Para mais detalhes, veja xwc.h, xwc.c e principalmente os programas de testes. Em particular, teste2.c contém testes de animação.

O objeto básico de trabalho no xwc é do tipo WINDOW. Este tipo corresponde a janelas e áreas de trabalho.

Inicialização e finalização.

Para abrir uma janela e inicializar o sistema, use a função

Para encerrar e liberar os recursos alocados, use

Desenhando

Existem várias funções de desenho. Todas elas permitem a especificação de uma cor, indicada através de um número inteiro. A correspondência entre número e cor depende da tabela (colormap) ativa no momento. Para alocar entradas nesta tabela e definir suas próprias cores, use:

No que segue, em geral, win se refere à janela destino e c é a cor.

As funções de desenho propriamente ditas são:

Existem outras funções de desenho no libX, que podem ser usadas. Dê uma olhada em xwc.c para ver como isso pode ser feito.

Área de rascunho

Áreas de desenho independentes de janelas são chamadas "PICs". Um PIC pode ter qualquer tamanho, mas deve estar associado a uma janela já existente.

Todas as funções de desenho podem ser indistintamente aplicadas a PICs da mesma forma que são aplicadas a janelas. Um PIC é equivalente a WINDOW *.

As funções específicas de PICs são:

Máscaras

Máscaras são figuras de duas cores que restringem a cópia de um pic em outro. Apenas os pixels correspondentes a pontos pintados na máscara são copiados. Isto permite criar áreas transparentes em retângulos. Na verdade as janelas de formatos genéricos usam esta técnica.

As funções de desenho se aplicam a máscaras da mesma forma que se aplicam a pics e janelas. A única restrição são as cores. Use apenas 0 e 1 como índice de cor.

As funções específicas são:

Veja teste2.c para ver uma utilização interessante de máscaras.

XPM

O formato XPM é um formato especial para indicar figuras no Xwindows. É um formato caro em termos de tamanho, mas fácil de mexer e documentar (é uma cadeia de caracteres, legível). teste3.c ilustra a utilização de arquivos e figuras neste formato.

As funções são:

Download da biblioteca

O tar.gz do xwc pode ser baixado deste link.


Allegro

Esta seção apresenta um pequeno resumo das funções da Allegro. Para mais detalhes, veja a página oficial da biblioteca, no SourceForge, especialmente os tutoriais que ensinam como utilizar as funções gráficas.

Seguem abaixo algumas instruções para se dar o pontapé inicial na utilização desta biblioteca.

Inicialização e finalização.

Para inicializar a biblioteca, use a função:

Para definir o número de cores, use a função: Para inicializar o modo gráfico, use a função:

Para encerrar e liberar os recursos alocados, use:

Bitmaps

A Allegro trabalha com objetos do tipo BITMAP. Bitmaps são matrizes de pixels, onde cada pixel representa uma cor. A tela é um tipo especial de BITMAP, chamado screen. Para alocar um objeto do tipo BITMAP:

Para desalocar um objeto do tipo BITMAP:

Desenhando

Dado um objeto do tipo BITMAP, você pode criar figuras nele; seguem abaixo algumas das várias funções de desenho:

A biblioteca Allegro oferece muitas outras funções além das aqui descritas, incluindo mais funções de desenho, manipulação de paleta de cores, de fontes, etc. Existem diversos tutoriais (inclusive em português) e exemplos pela Internet que as explicam em detalhes.

Download da biblioteca

A Allegro pode ser baixada na página oficial da biblioteca ou, dependendo da distro, através de algum gerenciador de pacotes (e.g. em Debian, utilizando o apt).


Tempo Real

Para controle do tempo real você poderá utilizar a seguinte função POSIX:

#include <time.h> 
int nanosleep(const struct timespec *requested, struct timespec *remaining);
Dê uma olhada na página de manual do nanosleep para ver como ele funciona.

Nesta fase do projeto, você pode iniciar o desenvolvimento gerando uma "foto" ou quadro por segundo, chamando a função nanosleep para dormir 1 bilhão de nanosegundos entre um quadro e outro. Depois que o seu programa estiver funcionando bem, você deve reconfigurá-lo para gerar 10 quadros por segundo para dar impressão de movimento (dormindo 100 milhões nanosegundos entre um quadro e outro). Lembre-se que 10 quadros por segundo é o número mínimo de vezes necessário que você deve redesenhar as espaçonaves (os asteróides e os cristais, que se movem mais lentamente, podem ser atualizados pelo menos 1 vez por segundo). Se o programa estiver funcionando muito bem, você pode ainda tentar 30 quadros por segundo, que é uma taxa comumente utilizada em vídeos e jogos.

Otimização do Joguinho:

Melhorar a simulação do tempo real medindo o tempo gasto no processamento de cada quadro e descontar esse tempo no tempo em que o programa dorme (com o nanosleep). Essa melhoria é importante quando se tem muitos quadros por segundo e muita coisa acontecendo (por exemplo, muitos asteróides e cristais, as espaçonavas se mexendo, música tocando etc.). Se você não implementar essa melhoria (que é obrigatória neste EP), há o perigo do seu jogo ficar muito lento caso tenha muita coisa acontecendo ou outros programas sendo executados na mesma máquina.

Para medir o tempo gasto no processamento de cada quadro, você pode usar, por exemplo:

   #include <sys/time.h>
   int gettimeofday(struct timeval *tv, struct timezone *tz);
Dê uma olhada na página de manual para aprender como ela funciona. Cuidado, pois ela devolve o tempo em microsegundos (10^-6 seg) e não em nanosegundos (10^-9 seg).


Data de entrega

A segunda fase deverá ser entregue até o dia 27 de maio (quarta-feira). Dúvidas podem ser discutidas no fórum da disciplina no Moodle, para o aproveitamento de todos.



Página de MAC211
Página do Fabio
Página do DCC