Академический Документы
Профессиональный Документы
Культура Документы
Os apêndices a seguir estão disponíveis como documentos PDF no site que acompanha o
livro (www.pearsonhighered.com/deitel/):
1. Apêndice E, Programação de jogos com a biblioteca C Allegro
2. Apêndice F, Classificação: uma visão mais detalhada
3. Apêndice G, Introdução ao padrão C99
4. Apêndice H, Usando o depurador do Visual Studio
5. Apêndice I, Usando o depurador GNU
® ®
Estes arquivos podem ser vistos no Adobe Reader (get.adobe.com/reader). As entradas de
índice para estes apêndices possuem números de página em formato de algarismos romanos.
Cópias novas deste livro vêm com um código de acesso ao site Web, localizado no
cartão por trás da capa do livro. Se o código de acesso já estiver visível ou se não houver
cartão, você comprou um livro usado ou uma edição que não vem com um código de
acesso. Nesse caso, você pode adquirir o acesso diretamente do site Web que acompanha o
livro.
Apêndice E
Objetivos
Neste capítulo, você aprenderá:
Como instalar a biblioteca de programação de jogos Allegro para que funcione com
seus programas em C.
A criar jogos usando o Allegro.
A importar e exibir gráficos.
A usar o ―buffering duplo‖ para criar animações suaves.
A importar e tocar sons.
A reconhecer e processar entrada do teclado.
A criar um jogo de Pong simples.
A usar timers para regular a velocidade de um jogo.
A usar datafiles de dados para encurtar a quantidade de código em um programa.
Esboço
E.1 Introdução
E.2 Instalando o Allegro
E.3 Um programa Allegro simples
E.4 Gráficos simples: Importando mapas de bits e blitando
E.5 Animação com buffering duplo
E.6 Importando e tocando sons
E.7 Entrada pelo teclado
E.8 Fontes e exibição de texto
E.9 Implementando o jogo de Pong
E.10 Timers no Allegro
E.11 O Grabber e datafiles do Allegro
E.12 Outras capacidades do Allegro
E.13 Allegro Resource Center
Resumo | Terminologia | Exercícios de autorrevisão | Respostas dos exercícios de autorrevisão | Exercícios
E.1 Introdução
Apresentamos agora a programação de jogos e gráficos com a biblioteca C Allegro. Criada
em 1995 pelo programador de jogos da Climax, Shawn Hargreaves, Allegro agora é um
projeto de fonte aberto mantido pela comunidade de desenvolvedores de jogos em
www.allegro.cc.
Neste apêndice, mostraremos como usar a biblioteca C Allegro para criar um jogo
de Pong simples. Demonstraremos como exibir gráficos e animar suavemente objetos em
movimento. Explicaremos recursos adicionais, como som, entrada do teclado, saída de texto
e timers, que são úteis na criação de jogos. O apêndice inclui links na Web para mais de
1.000 jogos Allegro de fonte aberto e tutoriais sobre técnicas avançadas em Allegro.
No Visual Studio 2008, vá até Tools > Options > Projects and Solutions > VC++
Directories e selecione Include files na combo Show Directories for:. Selecione uma linha em
branco e navegue pela pasta include incluída com o download do Allegro. Em seguida,
selecione Library files pela combo e navegue até a pasta lib. Finalmente, copie todos os
arquivos .dll da pasta bin incluída com o download do Allegro para a pasta C:\Windows\System32.
Quando a instalação estiver completa, você terá de dizer ao Visual Studio onde
encontrar a biblioteca Allegro quando criar um novo projeto. Para fazer isso, crie um novo
Win32 Project. No Win32 Application Wizard, selecione Windows application como tipo de
aplicação e marque a caixa Empty project. Quando o projeto tiver sido criado, vá até Project >
Properties, depois Configuration Properties > Linker > Input. Selecione Additional Dependencies
e inclua ―alleg.lib‖. Você precisa realizar essa etapa para cada projeto Allegro que criar. A
pasta de exemplos deste apêndice inclui um projeto vazio e a solução com a biblioteca
Allegro já acrescentada como uma dependência, que você poderá usar para executar os
programas.
Instalando o Allegro no Linux
A maioria das distribuições Linux possui pacotes pré-compilados para o Allegro, embora o
nome exato do pacote possa ser diferente. No Debian e em distribuições baseadas no
Debian, como Ubuntu, o pacote é liballegro4.2-dev; no Fedora ele se chama allegro; e no
openSUSE ele é dividido nos pacotes allegro-devel e allegro-tools. Instale o(s) pacote(s)
apropriado(s) e o pacote make usando o gerenciador de pacotes da sua distribuição (por
exemplo, Synaptic, PackageKit ou YaST).
O programa make torna a compilação mais fácil, permitindo que você armazene
instruções para compilar programas em um arquivo chamado Makefile, em vez de digitá-los na
linha de comandos toda vez que você criar o programa. Fornecemos um Makefile com os
exemplos para este apêndice simplesmente executar ―make‖ de dentro do diretório usará o
Makefile para compilar todos os exemplos no apêndice. Se você estiver criando seu próprio
projeto, poderá adaptar nosso Makefile ou usar o programa allegro-config, que mostra as opções
do compilador necessárias para compilar e ligar os programas Allegro.
3 #include <allegro.h>
4
5 int main( void )
6 {
9 return 0;
3 #include <allegro.h>
4
5 int main( void )
6 {
17 return 0;
Se a função tiver sucesso, ela retorna 0; caso contrário, ela retorna um valor diferente de 0.
Em geral, a maioria das funções do Allegro que podem falhar segue o mesmo paradigma.
Se você quiser, poderá inserir estruturas if em nosso programa para verificar se suas funções
funcionam corretamente e dizer ao programa como prosseguir se uma delas falhar, mas,
para economizar espaço, nossos programas de exemplo considerarão que todas as nossas
funções funcionam conforme deveriam.
O primeiro parâmetro da função set_gfx_mode é int card. Nas versões mais antigas do
Allegro, esse parâmetro era usado para dizer ao computador qual driver de placa de vídeo
utilizar, mas determinar qual driver funcionaria corretamente com um certo sistema e
programa era um processo difícil. Nas versões mais novas da biblioteca, diversos dos
chamados ―drivers mágicos‖ foram acrescentados para detectar os drivers do computador
automaticamente GFX_AUTODETECT, GFX_AUTODETECT_FULLSCREEN, GFX_AUTODETECT_WINDOWED
e GFX_SAFE (todos estes são constantes simbólicas definidas em allegro.h). Além de especificar
o driver a usar, passar ao parâmetro um dos valores anteriores também diz ao Allegro se ele
deve executar o programa em uma janela ou se o programa deve usar a tela cheia. Passar
GFX_AUTODETECT_FULLSCREEN ou GFX_AUTODETECT_WINDOWED diz ao programa para executar no
modo de tela cheia (o programa ocupa a tela inteira) ou no modo em janelas (o programa é
executado em uma janela padrão), respectivamente. Passar GFX_AUTODETECT faz o programa
tentar o modo de tela cheia primeiro, depois o modo em janela, se o modo de tela cheia
causar um erro. O modo GFX_SAFE geralmente não é usado; embora ele atue da mesma forma
que GFX_AUTODETECT, há um acréscimo. Se os modos de tela cheia e em janela falharem, o
modo GFX_SAFE força o computador a usar opções que ele ―sabe‖ que funcionarão. Porém,
esses modos ―seguros‖ normalmente possuem resolução e profundidade de cor
extremamente baixas, de modo que geralmente são evitados. Há também uma quinta
constante simbólica, GFX_TEXT, mas essa opção só permite texto, como o nome sugere, e
passar essa constante a set_gfx_mode basicamente ―desativará‖ qualquer gráfico em janela ou
em tela cheia que já estiver rodando.
Observação de engenharia de software E.1
Evite usar o “driver mágico” GFX_SAFE, se possível. Os modos gráficos “seguros”
geralmente possuem um impacto negativo sobre a aparência do seu programa.
Os dois parâmetros seguintes, width e height, determinam o número de pixels na largura
e altura da tela (ou da janela, se você estiver usando o modo em janela), respectivamente.
Os dois últimos parâmetros (v_w e v_h) definem a largura e altura mínima em pixels,
respectivamente, do que é chamada de ―tela virtual‖. A ―tela virtual‖ foi usada nas versões
anteriores do Allegro para ajudar a criar jogos onde a ação pode ocorrer fora da visão da
tela visível, mas não tem qualquer uso real na versão atual do Allegro, pois a maioria dos
sistemas hoje não admite isso. Assim, os parâmetros v_w e v_h devem simplesmente receber o
valor 0.
Agora que sabemos como definir o modo gráfico, vamos examinar a função na linha
13, load_bitmap. Essa função, apresentada na Figura E.2, carrega a figura que foi salva como
picture.bmp e faz com que o ponteiro bmp aponte para ela. Não passamos uma palheta à função
isso não é necessário. Lembre-se de que passar uma palheta do bitmap só é necessário
quando a profundidade de cor é definida como 8 bits, porém, é importante que você cuide
de definir a profundidade de cor e o modo gráfico no seu programa antes de tentar carregar
um arquivo de bitmap. Caso contrário, o Allegro não terá informações sobre como
armazenar o bitmap na memória (ele não saberá quantos bits na memória deverá usar para
cada pixel, por exemplo) e, ao invés disso, tentará ―adivinhar‖ como proceder. Isso pode
ocasionar vários erros no seu programa.
Como blit desenha um bitmap em outro, temos de especificar esses bitmaps para que a
função funcione. Os dois primeiros parâmetros (source e dest) definem os bitmaps de origem e
destino, respectivamente, de modo que, em nosso programa, estamos apanhando um bloco
de bmp e desenhando-o em screen. A constante simbólica screen (definida em allegro.h) refere-se
à tela do computador. O blitting na tela é um modo de exibir gráficos.
Como o blitting apanha um bloco de um bitmap, também temos de especificar a
posição desse bloco no bitmap de origem. Os parâmetros source_x e source_y especificam as
coordenadas do canto superior esquerdo do bloco que queremos desenhar no bitmap de
destino. As coordenadas de bitmap do Allegro não funcionam da mesma maneira que na
maioria dos gráficos em nossas aulas de álgebra e geometria: um valor x maior significa
mais à direita, mas um valor y maior significa mais para baixo, e não para cima. Isso
significa que o canto superior esquerdo de qualquer imagem de bitmap está nas coordenadas
(0, 0). A Figura E.4 ilustra esse sistema de coordenadas usando a saída do programa que
escrevemos na Figura E.3.
[F]Figura E.4 Sistema de coordenadas do Allegro.
Para desenhar em um bitmap, também temos de dizer à função onde queremos que o
desenho ocorra. Os parâmetros dest_x e dest_y determinam as coordenadas do ponto superior
esquerdo desse local. Novamente, as coordenadas (0, 0) representam o canto superior
esquerdo de um bitmap.
Finalmente, embora tenhamos especificado o canto superior esquerdo do bloco que
queremos copiar do nosso bitmap de origem, ainda não especificamos seu tamanho. Os dois
últimos parâmetros especificam a largura (width) e a altura (height) do bloco que estamos
―blitando‖. Você pode estar se perguntando por que, em nosso programa, pudemos passar a
esses parâmetros os valores bmp->w e bmp->h. O motivo para isso é que o tipo BITMAP* definido
pelo Allegro é um ponteiro para uma struct. Junto com os dados de imagem e algumas outras
variáveis, a struct BITMAP contém dois ints, w e h, que representam a largura e a altura do
bitmap, respectivamente. A menos que você não queira mostrar a imagem inteira, deverá
passar a esses parâmetros os valores bmp->w e bmp->h, substituindo bmp pelo nome do seu
bitmap.
A função blit que chamamos na linha 14, então, copia um bloco de bmp, cujo canto
superior esquerdo e tamanho são aqueles de bmp, e o desenha no canto superior esquerdo da
tela virtual. Resumindo, ela mostra a imagem contida em picture.bmp no canto superior
esquerdo da tela.
Depois de blitar a imagem na tela, o programa faz uma chamada à função readkey.
Essa função é o motivo pelo qual chamamos install_keyboard anteriormente no programa. A
função readkey espera que uma tecla seja pressionada, depois retorna o valor da tecla
pressionada como um int. Embora não façamos nada com o valor que ela retorna, essa
função é útil nesse programa porque, como scanf, ele faz com que o programa pare até que o
usuário forneça alguma entrada. Sem ela, o programa terminaria antes que tivéssemos a
chance de ver o bitmap.
Finalmente, após pressionarmos uma tecla, o programa chama destroy_bitmap.
Conforme já explicamos, essa função destrói o bitmap passado a ela e realiza o equivalente
da função free sobre a memória que foi alocada a ele.
Dica de prevenção de erro E.1
Use a função destroy_bitmap para liberar a memória de um bitmap que não é mais
necessário e impedir perdas de memória.
Erro comum de programação E.3
Tentar destruir um bitmap que não foi inicializado causa um erro em tempo de
execução.
3 #include <allegro.h>
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
12 void moveBall( void );
13 void reverseVerticalDirection( void );
14 void reverseHorizontalDirection( void );
15
16 int ball_x; /* a coordenada-x da bola */
17 int ball_y; /* a coordenada-y da bola */
18 int direction; /* a direção da bola */
19 BITMAP *ball; /* ponteiro para o bitmap de imagem da bola */
20
21 int main( void )
22 {
23 /* primeiro, configura o Allegro e o modo gráfico */
35 {
36 moveBall(); /* move a bola */
40 } /* fim do while */
41
42 destroy_bitmap( ball ); /* destrói o bitmap da bola */
43 return 0;
50 case DOWN_RIGHT:
53 break;
54 case UP_RIGHT:
57 break;
58 case DOWN_LEFT:
61 break;
62 case UP_LEFT:
65 break;
66 } /* fim do switch */
67
68 /* cuida para que a bola não saia da tela */
69
70 /* se a bola está saindo acima ou abaixo... */
Essa função retorna um int que representa a cor com as intensidades de vermelho
(Red), verde (Green) e azul (Blue) especificadas. As intensidades permitidas podem variar
de 0 a 255, de modo que passar os valores ( 255, 0, 0 ) criará uma cor vermelha brilhante, ( 0,
255, 0 ) criará um verde brilhante e ( 0, 0, 255 ) criará um azul brilhante. Na Figura E.5,
passamos ( 255, 255, 255 ), ou a intensidade máxima de todas as três cores, que cria o branco.
Isso significa que nosso programa definirá a cor da tela como branca quando a função
clear_to_color for chamada. A Figura E.6 mostra uma tabela de cores comuns e seus valores
vermelho, verde e azul.
Cor Valor de Red Valor de Green Valor de Blue
Red 255 0 0
Green 0 255 0
Blue 0 0 255
Orange 255 200 0
Pink 255 175 175
Cyan 0 255 255
Magenta 255 0 255
Yellow 255 255 0
Black 0 0 0
White 255 255 255
Gray 128 128 128
Light gray 192 192 192
Dark gray 64 64 64
[F]Figura E.6 As intensidades de vermelho, verde e azul das cores comuns no Allegro.
O restante do programa é autoexplicativo fazemos a bola se mover pela tela e,
quando ela atinge uma borda, ela muda sua direção de modo que ―quique‖. O motivo para
as linhas em moveBall e as duas funções reverseDirection estarem destacadas é que a matemática
pode parecer um pouco estranha. Primeiro, verificamos se a bola está saindo da tela nas
linhas 71 e 75. Você pode estar se perguntando por que os limites direito e inferior de nossa
tela parecem ser 600 e 440 nessas instruções if, ao invés de 640 e 480 (o tamanho real da
tela). Lembre-se de que, quando blitamos um bitmap na tela, passamos a ele o canto
superior esquerdo do bloco em que queremos desenhar. Isso significa que, se ball_y tem um
valor de 440, seu limite superior será na coordenada y 440. Porém, como a bola tem 40
pixels de altura, seu limite inferior na realidade será na coordenada y 480, que é a borda
inferior da tela. O mesmo se aplica à coordenada x da bola, que explica por que o maior
valor que ela pode ter é 600. Além disso, se você está se perguntando por que o menor valor
y permitido é 30, isso é simplesmente porque usaremos os 30 pixels superiores da tela para
o placar quando acrescentarmos mais ao nosso jogo de Pong.
Considere as linhas que mudam a direção da bola. A linha 82 faz com que a bola
comece a subir se estiver atualmente descendo, enquanto a linha 84 faz o contrário. A linha
89 faz a bola começar a mover para a esquerda se estiver atualmente se movendo para a
direita, e para a direita se estiver atualmente se movendo para a esquerda. Por que isso
funciona? Devido aos valores específicos das constantes simbólicas (linhas 6-9), realizarem
as operações nessas três linhas sempre o levará na direção que você deseja.
Nossa ―bola‖ é um quadrado, e não um círculo. Isso não tem muito impacto sobre
nosso programa agora, mas, quando acrescentarmos raquetes em nosso jogo, ter uma bola
quadrada torna muito mais fácil detectar se a bola e as raquetes estão se tocando. Veremos
mais detalhes sobre essa questão na Seção E.9, quando incluirmos esse recurso em nosso
jogo.
Execute o programa e você verá sua bola quicando na tela. Observe, porém, que a
tela pisca muito enquanto a bola se move, ao ponto de ser difícil ver a bola. Para resolver
isso, apresentamos uma técnica chamada buffering duplo.
Buffering duplo para a animação suave
Se você executasse o programa da seção anterior, provavelmente notaria que a tela piscava
enquanto a bola se movia. Por que isso acontece? Lembre-se de que, para nossa animação
funcionar, tivemos de apagar a tela toda vez que a bola se movia. Infelizmente, essa não é a
melhor prática. Embora a maioria dos computadores possa apagar e redesenhar a tela
rapidamente, ainda existe algum tempo em que a tela fica em branco entre o momento no
qual é apagada e quando a bola é impressa nela. Embora a tela esteja vazia apenas
rapidamente, ainda é suficiente para fazer com que a tela pareça piscar enquanto move a
bola, pois a bola continua se apagando antes de ser redesenhada.
Podemos consertar isso com uma técnica chamada buffering duplo, que usa um
bitmap intermediário, do tamanho da tela, chamado de buffer, para tornar a animação dos
bitmaps em movimento mais suave. Em vez de apresentarmos os bitmaps na tela,
imprimimos os objetos que queremos que o usuário veja no buffer. Quando tudo o que
quisermos estiver lá, imprimimos o buffer na tela e apagamos o buffer.
Por que isso funciona? Você notará que nunca apagamos a tela quando usamos essa
técnica. Em vez de apagar tudo antes de redesenhar as imagens na tela, simplesmente
desenhamos sobre o que já está lá, o que elimina as piscadas que o programa na Figura E.5
produziu quando apagou a tela. Além disso, como o buffer não é visível ao usuário (lembre-
se de que o usuário só pode ver a screen), podemos imprimir e apagar o buffer sem nos
preocuparmos se isso afeta algo que o usuário vê. A Figura E.7 mostra essa técnica na
prática.
1 /* Figura E.7: figE_07.c
3 #include <allegro.h>
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
23 {
37 {
43 clear_bitmap( buffer );
44 } /* fim do while */
45
46 destroy_bitmap( ball ); /* destrói o bitmap da bola */
48 return 0;
53 {
54 switch ( direction ) {
55 case DOWN_RIGHT:
58 break;
59 case UP_RIGHT:
62 break;
63 case DOWN_LEFT:
66 break;
67 case UP_LEFT:
70 break;
71 } /* fim do switch */
72
73 /* cuida para que a bola não saia da tela */
74
75 /* se a bola está saindo acima ou abaixo ... */
77 reverseVerticalDirection();
78
79 /* se a bola está saindo para a esquerda ou para a direita ... */
81 reverseHorizontalDirection();
85 {
93 {
A função retorna um int para fins de verificação de erro 0 se a função tiver sucesso e um
valor diferente de 0 em caso contrário. Os parâmetros digi e midi especificam os drivers de
placa de som usados para tocar amostras digitais e arquivos MIDI, respectivamente. Assim
como os drivers gráficos, as versões mais novas do Allegro oferecem os chamados ―drivers
mágicos‖ que automaticamente especificam os drivers de áudio a usar DIGI_AUTODETECT e
MIDI_AUTODETECT. Estes são os únicos valores que você deverá passar aos dos primeiros
parâmetros.
O parâmetro cfg_path não tem efeito sobre o programa. Versões mais antigas do
Allegro exigiam que você especificasse um arquivo .cfg que dizia ao programa como tocar
arquivos de som, mas isso não é mais necessário na versão atual.
Agora, vamos acrescentar sons ao programa da bola que quica. Assim como
bitmaps, temos de fornecer ao programa um arquivo de som externo para carregar; portanto,
copie o arquivo de som boing.wav dos exemplos do apêndice e salve-o na mesma pasta do seu
projeto pong. Depois, podemos usar o código na Figura E.9 para fazer nossa bola emitir um
som de ―boing‖ sempre que ela quicar em uma margem da tela. As linhas destacadas
marcam as mudanças da seção anterior.
1 /* Figura E.9: figE_09.c
3 #include <allegro.h>
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
12 void moveBall( void );
13 void reverseVerticalDirection( void );
14 void reverseHorizontalDirection( void );
15
16 int ball_x; /* a coordenada-x da bola */
17 int ball_y; /* a coordenada-y da bola */
18 int direction; /* a direção da bola */
19 BITMAP *ball; /* ponteiro para o bitmap de imagem da bola */
20 BITMAP *buffer; /* ponteiro para o buffer */
21 SAMPLE *boing; /* ponteiro para arquivo de som */
22
23 int main( void )
24 {
25 /* primeiro, configura o Allegro e o modo gráfico */
39 {
45 clear_bitmap( buffer );
46 } /* fim do while */
50 return 0;
57 case DOWN_RIGHT:
60 break;
61 case UP_RIGHT:
64 break;
65 case DOWN_LEFT:
68 break;
69 case UP_LEFT:
70 --ball_x; /* move a bola para a esquerda */
72 break;
73 } /* fim do switch */
74
75 /* cuida para que a bola não saia da tela */
76
77 /* se a bola está saindo acima ou abaixo ... */
79 reverseVerticalDirection();
80
81 /* se a bola está saindo para a esquerda ou para a direita ... */
83 reverseHorizontalDirection();
92 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
98 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
3 #include <allegro.h>
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
16
17 int ball_x; /* coordenada-x da bola */
28 {
45
46 while ( !key[KEY_ESC] ) /* até que a tecla Escape seja pressionada ... */
47 {
56 clear_bitmap( buffer );
57 } /* fim do while */
58
59 destroy_bitmap( ball ); /* destrói o bitmap da bola */
63 return 0;
66
67 void moveBall() /* move a bola */
68 {
69 switch ( direction ) {
70 case DOWN_RIGHT:
73 break;
74 case UP_RIGHT:
77 break;
78 case DOWN_LEFT:
81 break;
82 case UP_LEFT:
85 break;
86 } /* fim do switch */
87
88 /* cuida para que a bola não saia da tela */
89
90 /* se a bola está saindo acima ou abaixo ... */
93
94 /* se a bola está saindo para a esquerda ou para a direita ... */
96 reverseHorizontalDirection();
98
99 void respondToKeyboard() /* responde à entrada do teclado */
100 {
105
106 if ( key[KEY_UP] ) /* se a seta para cima estiver sendo pressionada... */
110
111 /* cuida para que as raquetes não saiam da tela */
114 else if ( barL_y > 380 ) /* se a raquete esquerda estiver saindo por baixo */
118 else if ( barR_y > 380 ) /* se a raquete direita estiver saindo por baixo */
121
122 void reverseVerticalDirection() /* inverte a direção acima-abaixo da bola */
123 {
128 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
130
131 void reverseHorizontalDirection() /* inverte a direção horizontal */
132 {
134 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
O primeiro parâmetro, obviamente, é o nome do arquivo de fonte que está sendo carregado.
O segundo parâmetro é algo que já vimos uma palheta. Porém, assim como bitmaps, se a
profundidade de cor não for 8 bits, não temos realmente de passar uma palheta para a
função. Ela pode ser seguramente NULL, sem qualquer consequência. Não usaremos o
terceiro parâmetro ele é usado para dizer ao Allegro para carregar fontes de diferentes
maneiras, o que não precisamos fazer. Assim como o segundo parâmetro, ele pode ser
definido como NULL sem causar quaisquer problemas. Quando uma fonte tiver sido
carregada, você poderá usar as funções na Figura E.11 para desenhar texto em um bitmap
ou na tela.
Protótipo de função Descrição
void textprintf_ex(BITMAP *bmp, Desenha a string de controle de formato
const FONT *f, int x, int y, especificada por fmt e os parâmetros
seguintes no bmp nas coordenadas
int color, int bgColor,
especificadas. O texto é desenhado na fonte
const char *fmt, ...)
e em cores especificadas, e fica alinhado à
esquerda.
...)
...)
"Hello!" );
Esta chamada de função mostra a string "Hello!" no canto superior esquerdo de um buffer (que
pode ser desenhada mais tarde na tela), usando a fonte default. O texto é exibido em preto,
com uma cor de fundo transparente.
A string que passamos à função textprintf_ex é uma string de controle de formato. Isso
significa que podemos usar qualquer um dos especificadores de conversão discutidos no
Capítulo 9 para imprimir ints, doubles e outras variáveis. Isso é muito útil se, por exemplo,
quisermos imprimir o escore de um jogador, como precisaremos fazer em nosso jogo Pong.
Passamos ao parâmetro bgColor um valor -1 na chamada de exemplo. O Allegro não
pode criar essa cor com uma chamada a makecol, pois ela interpreta o valor de -1 como ―sem
cor‖ ou ―transparente‖. Isso significa que o texto exibido não terá cor de fundo e que
qualquer coisa ―por trás‖ do texto será visível.
Normalmente, a fonte default do Allegro serve para a exibição de texto, mas
fornecemos o arquivo de fonte pongfont.pcx com os exemplos do apêndice, para uso com nosso
programa. Em nosso jogo de Pong, usamos as funções descritas anteriormente para exibir os
escores de cada um dos jogadores. Por esse motivo, acrescentamos os ints, scoreL e scoreR a
essa iteração do programa. Observe, porém, que como as raquetes ainda não fazem nada,
não podemos manter o escore no jogo, e portanto os valores de scoreL e scoreR permanecerão
em 0 durante o programa. Apesar disso, a Figura E.12 mostra como usar as funções
explicadas anteriormente para exibir texto na tela usando a fonte fornecida em nosso site.
1 /* Figura E.12: figE_12.c
3 #include <allegro.h>
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
16
17 int ball_x; /* coordenada-x da bola */
29
30 int main( void )
31 {
51
52 while ( !key[KEY_ESC] ) /* até que a tecla Escape seja pressionada ... */
53 {
67 clear_bitmap( buffer );
68 } /* fim do while */
69
70 destroy_bitmap( ball ); /* destrói o bitmap da bola */
75 return 0;
78
79 void moveBall() /* move a bola */
80 {
81 switch ( direction ) {
82 case DOWN_RIGHT:
85 break;
86 case UP_RIGHT:
89 break;
90 case DOWN_LEFT:
93 break;
94 case UP_LEFT:
97 break;
98 } /* fim do switch */
99
100 /* cuida para que a bola não saia da tela */
101
102 /* se a bola está saindo acima ou abaixo ... */
104 reverseVerticalDirection();
105
106 /* se a bola está saindo para a esquerda ou para a direita ... */
107 if ( ball_x <= 0 || ball_x >= 600 )
108 reverseHorizontalDirection();
110
111 void respondToKeyboard() /* responde à entrada do teclado */
112 {
117
118 if ( key[KEY_UP] ) /* se seta para cima estiver sendo pressionada... */
122
123 /* cuida para que as raquetes não saiam da tela */
126 else if ( barL_y > 380 ) /* se a raquete esquerda estiver saindo por baixo */
130 else if ( barR_y > 380 ) /* se a raquete direita estiver saindo por baixo */
133
134 void reverseVerticalDirection() /* inverte a direção acima-abaixo da bola */
135 {
142
143 void reverseHorizontalDirection() /* inverte a direção horizontal */
144 {
146 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
Essa função desenha uma linha reta no bitmap especificado a partir das coordenadas (x1, y1)
até as coordenadas (x2, y2). A linha será desenhada na cor indicada, que pode ser
especificada usando a função makecol. Agora, podemos colocar os retoques finais em nosso
jogo de Pong com o código da Figura E.13.
1 /* Figura E.13: figE_13.c
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
16
17 int ball_x; /* coordenada-x da bola */
29
30 int main( void )
31 {
51
52 while ( !key[KEY_ESC] ) /* até que a tecla Escape seja pressionada ... */
53 {
69 } /* fim do while */
70
71 destroy_bitmap( ball ); /* destrói o bitmap da bola */
76 return 0;
79
80 void moveBall() /* move a bola */
81 {
82 switch ( direction ) {
83 case DOWN_RIGHT:
86 break;
87 case UP_RIGHT:
90 break;
91 case DOWN_LEFT:
94 break;
95 case UP_LEFT:
98 break;
99 } /* fim do switch */
100
101 /* se a bola está saindo acima ou abaixo ... */
103 reverseVerticalDirection();
104
105 /* se a bola estiver no alcance da raquele esquerda ... */
107 {
110 reverseHorizontalDirection();
117 } /* fim do if */
118
119 /* se a bola estiver no alcance da raquele direita ... */
121 {
124 reverseHorizontalDirection();
131 } /* fim do if */
133
134 void respondToKeyboard() /* responde à entrada do teclado */
121 {
126
127 if ( key[KEY_UP] ) /* se seta para cima estiver sendo pressionada... */
131
132 /* cuida para que as raquetes não saiam da tela */
135 else if ( barL_y > 380 ) /* se a raquete esquerda estiver saindo por baixo */
139 else if ( barR_y > 380 ) /* se a raquete direita estiver saindo por baixo */
156
157 void reverseVerticalDirection() /* inverte a direção acima-abaixo da bola */
158 {
163 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
165
166 void reverseHorizontalDirection() /* inverte a direção horizontal */
167 {
169 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
Você notará que o parâmetro function é um ponteiro de função. Chamar a função install_int
acrescenta um timer ao seu programa, que chama a função especificada por function a cada
interval milissegundos. Assim, se quiséssemos chamar uma função timedFunction uma vez a cada
segundo, incluiríamos o seguinte código:
install_int( timedFunction, 1000 );
3 #include <allegro.h>
4
5 /* Constantes simbólicas para as direções de posição da bola */
6 #define DOWN_RIGHT 0
7 #define UP_RIGHT 1
8 #define DOWN_LEFT 2
9 #define UP_LEFT 3
10
11 /* protótipos de função */
16
17 volatile int ball_x; /* coordenada-x da bola */
29
30 int main( void )
31 {
53 install_int( moveBall, 5 );
55 install_int( respondToKeyboard, 10 );
56
57 while ( !key[KEY_ESC] ) /* até que a tecla Escape seja pressionada ... */
58 {
71 clear_bitmap( buffer );
72 } /* fim do while */
73
74 remove_int( moveBall ); /* remove timer moveBall */
81 return 0;
84
85 void moveBall() /* move a bola */
86 {
87 switch ( direction ) {
88 case DOWN_RIGHT:
91 break;
92 case UP_RIGHT:
95 break;
96 case DOWN_LEFT:
99 break;
103 break;
105
106 /* se a bola está saindo acima ou abaixo ... */
108 reverseVerticalDirection();
109
110 /* se a bola estiver no alcance da raquele esquerda ... */
112 {
115 reverseHorizontalDirection();
122 } /* fim do if */
123
124 /* se a bola estiver no alcance da raquele direita ... */
126 {
129 reverseHorizontalDirection();
136 } /* fim do if */
138
139 void respondToKeyboard() /* responde à entrada do teclado */
132 {
137
138 if ( key[KEY_UP] ) /* se seta para cima estiver sendo pressionada... */
146 else if ( barL_y > 380 ) /* se a raquete esquerda estiver saindo por baixo */
150 else if ( barR_y > 380 ) /* se a raquete direita estiver saindo por baixo */
153
154 void reverseVerticalDirection() /* inverte a direção acima-abaixo da bola */
155 {
160 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
162
163 void reverseHorizontalDirection() /* inverte a direção horizontal */
164 {
166 play_sample( boing, 255, 128, 1000, 0 ); /* toca som "boing" uma vez */
2 /* Datafile: c:\examples\appE\pongdatafile.dat */
2 Usando datafiles. */
3 #include <allegro.h>
4 #include "pong.h"
5
6 /* Constantes simbólicas para as direções de posição da bola */
7 #define DOWN_RIGHT 0
8 #define UP_RIGHT 1
9 #define DOWN_LEFT 2
10 #define UP_LEFT 3
11
12 /* protótipos de função */
17
18 volatile int ball_x; /* coordenada-x da bola */
27
28 int main( void )
29 {
48 install_int( moveBall, 5 );
50 install_int( respondToKeyboard, 10 );
51
52 while ( !key[KEY_ESC] ) /* até que a tecla Escape seja pressionada ... */
53 {
66 clear_bitmap( buffer );
67 } /* fim do while */
68
69 remove_int( moveBall ); /* remove timer moveBall */
73 return 0;
74 } /* fim da função main */
76
77 void moveBall() /* move a bola */
78 {
79 switch ( direction ) {
80 case DOWN_RIGHT:
83 break;
84 case UP_RIGHT:
87 break;
88 case DOWN_LEFT:
91 break;
92 case UP_LEFT:
95 break;
96 } /* fim do switch */
97
98 /* se a bola está saindo acima ou abaixo ... */
100 reverseVerticalDirection();
101
102 /* se a bola estiver no alcance da raquele esquerda ... */
104 {
114 } /* fim do if */
115
116 /* se a bola estiver no alcance da raquele direita ... */
118 {
121 reverseHorizontalDirection();
128 } /* fim do if */
130
131 void respondToKeyboard() /* responde à entrada do teclado */
132 {
137
138 if ( key[KEY_UP] ) /* se seta para cima estiver sendo pressionada... */
142
143 /* cuida para que as raquetes não saiam da tela */
146 else if ( barL_y > 380 ) /* se a raquete esquerda estiver saindo por baixo */
150 else if ( barR_y > 380 ) /* se a raquete direita estiver saindo por baixo */
153
154 void reverseVerticalDirection() /* inverte a direção acima-abaixo da bola */
155 {
162
163 void reverseHorizontalDirection() /* inverte a direção horizontal */
164 {
Resumo
Seção E.3 Um programa Allegro simples
• Todo programa em Allegro precisa incluir o cabeçalho allegro.h, chamar a função allegro_init e
precisa ter uma chamada para a macro END_OF_MAIN imediatamente após a chave de
fechamento da função main do programa.
• A função allegro_init inicializa a biblioteca do Allegro. Ela precisa ser chamada antes de
quaisquer outras funções do Allegro, ou então o programa não funcionará corretamente.
• A função allegro_message é usada para dar ao usuário uma mensagem quando não houver
um modo gráfico de fazer isso.
• Windows, alguns sistemas Unix e Mac OS X não podem executar programas Allegro sem
a macro END_OF_MAIN. Se ela estiver faltando, os compiladores nesses sistemas não
poderão compilar um programa em Allegro. Não deixe de incluir a macro END_OF_MAIN
para garantir compatibilidade com sistemas que a exigem.
Seção E.4 Gráficos simples: Importando mapas de bits e blitando
• A maioria dos gráficos do Allegro vem de arquivos externos. O Allegro define diversos
tipos de variável diferentes, que apontam para dados de imagem na memória.
• O tipo BITMAP* é o tipo mais básico definido pelo Allegro para apontar para dados de
imagem armazenados na memória.
• A função set_color_depth é usada para definir a profundidade de cor de um programa em
Allegro. A profundidade de cor pode ser definida como 8, 15, 16, 24 ou 32 bits. Uma
profundidade de cor mais baixa requer menos memória, porém uma profundidade de cor
mais alta resulta em um programa com melhor aparência.
• A função set_gfx_mode é usada para definir o modo gráfico de um programa em Allegro.
Além de definir como o programa é exibido (ou seja, modo de tela cheia ou em janela),
ela também define quantos pixels existem na largura e altura da tela ou janela.
• O Allegro define cinco ―drivers mágicos‖ que podem ser passados à função set_gfx_mode
para especificar se o programa deve ser executado no modo de tela cheia ou em janela
GFX_AUTODETECT, GFX_AUTODETECT_FULLSCREEN, GFX_AUTODETECT_WINDOWED, GFX_SAFE e
GFX_TEXT.
• A maioria das funções em Allegro que podem falhar retornam ints para fins de verificação
de erro. Em geral, essas funções retornarão 0 se tiverem sucesso e um valor diferente de 0
se não tiverem.
• Um programa em Allegro precisa definir a profundidade de cor e o modo gráfico de um
programa antes de tentar fazer algo mais com os gráficos.
• A função create_bitmap cria um novo bitmap em branco.
• Use a função load_bitmap para carregar uma imagem de um arquivo de bitmap externo. Se a
profundidade de cor for definida como 8 bits, você precisa passar a essa função a palheta
do bitmap, além da própria imagem.
• Se a função load_bitmap falhar, ela retorna NULL. Ela não causa um erro.
• A função blit é uma das funções mais importantes no Allegro. Ela é usada para desenhar
um bloco de um bitmap para outro bitmap.
• Uma coordenada x maior corresponde a avançar para a direita no Allegro, mas uma
coordenada y maior corresponde a descer mais, e não subir.
• O tipo BITMAP* é um ponteiro para uma struct. Essa estrutura contém dois ints, w e h, que
armazenam a largura e a altura do bitmap em pixels, respectivamente.
• Use a função destroy_bitmap para destruir um bitmap e liberar a memória alocada a ele para
impedir perdas de memória.
Seção E.5 Animação com buffering duplo
• A animação no Allegro é feita blitando um objeto na tela em diferentes locais, em
intervalos regulares.
• As constantes simbólicas SCREEN_W e SCREEN_H são reservadas pelo Allegro e
correspondem à largura e à altura da tela em pixels, respectivamente.
• Use a função clear_to_color para tornar a totalidade de um bitmap de uma certa cor. Isso é
útil para definir uma cor de fundo para um programa.
• A função makecol é usada para retornar ints que o Allegro reconhece como várias cores.
• A técnica de ―buffering duplo‖ é um método que produz animação suave. A técnica
consiste em desenhar tudo em um bitmap intermediário, conhecido como buffer, e depois
desenhar todo o buffer na tela.
Seção E.6 Importando e tocando sons
• O Allegro define o tipo SAMPLE* que aponta para os dados do arquivo de som armazenados
na memória.
• Antes que quaisquer sons possam ser tocados no Allegro, a função install_sound precisa ser
chamada.
• O Allegro define dois ―drivers mágicos‖ que devem ser passados à função install_sound de
modo que o Allegro possa determinar quais drivers de placa de som ele deve usar para
tocar os sons. Esses ―drivers mágicos‖ são DIGI_AUTODETECT e MIDI_AUTODETECT.
• A função load_sample é usada para carregar um arquivo de som externo.
• Use a função play_sample para tocar uma amostra digital e a função stop_sample para
interrompê-la.
• O parâmetro volume na função play_sample determina o volume em que a amostra deve ser
tocada. Um valor 0 torna a amostra muda, enquanto um valor 255 a toca no volume
máximo.
• O parâmetro pan na função play_sample determina a posição de pan em que a amostra deve
ser tocada. Um valor 128 toca a amostra nos dois alto-falantes por igual. Um valor
inferior a este deslocará o som para o alto-falante da esquerda, enquanto um valor maior
(até um máximo de 255) deslocará o som para o alto-falante da direita.
• O parâmetro frequency na função play_sample determina a frequência (e, portanto, o pitch) em
que a amostra deverá ser tocada. Um valor 1000 tocará a amostra em frequência normal.
Um valor 2000 a tocará no dobro da frequência normal, um valor de 500 a tocará na
metade da frequência, e assim por diante.
• Passar um valor 0 ao parâmetro loop da função play_sample fará a amostra tocar apenas uma
vez antes de parar. Passar-lhe qualquer outro valor fará com que a amostra crie um loop
contínuo.
• Use a função destroy_sample para destruir uma amostra e liberar a memória alocada a ela
para impedir perdas de memória.
Seção E.7 Entrada pelo teclado
• Você precisa chamar a função install_keyboard para permitir que o Allegro reconheça e use o
teclado.
• O Allegro define um array de ints chamado key, que contém um índice para cada tecla no
teclado. Se uma tecla não estiver sendo pressionada, seu respectivo índice no array terá 0,
enquanto se a tecla estiver sendo pressionada, o índice terá um número diferente de 0.
• O Allegro define várias constantes simbólicas que correspondem às teclas no teclado.
Essas constantes são usadas em conjunto com o array key para determinar se teclas
específicas estão sendo pressionadas. O valor armazenado em key[KEY_A] determina se a
tecla A está ou não sendo pressionada, o valor armazenado em key[KEY_SPACE] determina se
a barra de espaço está sendo pressionada, e assim por diante.
• Qualquer programa que verifique a entrada do teclado usando o array key deve fazer isso
repetidamente. Caso contrário, as teclas pressionadas podem ser perdidas.
Seção E.8 Fontes e exibição de texto
• O Allegro define o tipo FONT* que aponta para dados de fonte armazenados na memória.
• A constante simbólica font corresponde à fonte default do Allegro.
• Use a função load_font para carregar os dados de fonte dos arquivos externos. Se a
profundidade de cor for definida para 8 bits, é preciso passar a palheta da fonte a essa
função, além da própria fonte.
• A função textprintf_ex imprime texto na tela. As funções textprintf_centre_ex e textprintf_right_ex
fazem a mesma coisa, mas alinham o texto impresso em diferentes posições.
• Quando o Allegro está esperando um int que corresponde a uma cor como parâmetro,
passar um valor -1 ao parâmetro fará com que o Allegro interprete essa cor como
―transparente‖.
• Use a função destroy_font para destruir uma fonte e liberar a memória alocada a ela, para
impedir perdas de memória.
Seção E.10 Timers no Allegro
• Qualquer programa que use timers precisa chamar a função install_timer antes de tentar
acrescentar quaisquer timers.
• O Allegro pode ter até 16 timers rodando ao mesmo tempo.
• Os timers são acrescentados chamando a função install_int e removidos chamando a função
remove_int.
• Um timer chama determinada função em intervalos regulares até que ele seja removido.
Não é preciso armazenar um timer em qualquer tipo de variável.
• O Allegro identifica um timer pela função que ele está programado a chamar.
• Qualquer variável cujo valor é modificado por uma função que um timer chama precisa
receber o qualificador volatile para garantir que o programa funcione corretamente.
Seção E.11 O Grabber e datafiles do Allegro
• Um datafile do Allegro é um único arquivo externo que mantém os dados de muitos
arquivos externos em um só lugar.
• O Allegro fornece o utilitário grabber para a criação e edição de datafiles.
• O grabber pode criar arquivos de cabeçalho que simplificam o acesso a objetos contidos
em um datafile.
• A função load_datafile carrega um datafile em um programa, e a função unload_datafile o
remove.
• Quando um datafile é carregado em um programa, o Allegro o considera como um array
de objetos. O índice de cada objeto no array é dependente da ordem em que os objetos
foram importados para o datafile. O primeiro objeto acrescentado ao datafile tem índice 0,
o segundo tem índice 1, e assim por diante.
• O Allegro considera os objetos carregados de um datafile como sendo do tipo void *.
Terminologia
Allegro II
blit VII
datafile XLIII
grabber XLII, XLIII, XLVI
set_gfx_mode VI
Exercícios de autorrevisão
E.1 Preencha os espaços em cada uma das seguintes sentenças:
a) Todo programa em Allegro precisa incluir o cabeçalho ______.
b) A função ______ precisa ser chamada antes de qualquer outra função no Allegro.
c) A inclusão da macro ______ garante compatibilidade com os sistemas que a
exigem.
d) Antes que o Allegro possa exibir quaisquer gráficos, um programa precisa chamar
as funções ______ e ______.
e) A função ______ é usada para desenhar um bloco de um bitmap em outro.
f) O principal tipo definido pelo Allegro para apontar para dados do arquivo de som
é o tipo ______.
g) O Allegro define a constante simbólica ______ que corresponde à fonte default do
Allegro.
h) A função ______ é usada para retornar um inteiro que o Allegro interpreta como
uma cor.
i) O Allegro pode ter até ______ timers em execução ao mesmo tempo.
j) A função ______ é usada para acrescentar um timer a um programa.
k) O utilitário ______ é usado para criar e editar datafiles do Allegro.
E.2 Indique se cada uma das seguintes sentenças é verdadeira ou falsa. Se for falsa,
explique o motivo.
a) O bitmap screen é o único bitmap visível ao usuário.
b) As coordenadas (0, 0) referem-se ao canto inferior esquerdo de um bitmap.
c) Se o Allegro tentar carregar um arquivo externo que não existe, será gerado um erro
em tempo de execução.
d) A técnica de buffering duplo requer dois bitmaps intermediários, ou buffers, para
que funcione corretamente.
e) Passar um valor 2 ao parâmetro loop na função play_sample fará com que o arquivo de
som toque duas vezes antes de parar.
f) A função install_keyboard precisa receber um parâmetro que dê ao Allegro a informação
de driver do teclado do sistema.
g) Um programa que desenha texto na tela precisa especificar uma fonte em que esse
texto deve ser desenhado.
h) Um programa em Allegro pode ter até 32 timers rodando ao mesmo tempo.
i) A função usada para liberar a memória que está armazenando um datafile é a função
destroy_datafile.
c) makecol( 0, 0, 256 );
E.2
a) Verdadeiro.
b) Falso. As coordenadas (0, 0) referem-se ao canto superior esquerdo de um bitmap.
c) Falso. A função que retorna o ponteiro para o arquivo externo retornará NULL, mas
nenhum erro ocorrerá nessa linha.
d) Falso. O buffering duplo requer apenas um bitmap intermediário.
e) Falso. Passar qualquer valor diferente de 0 ao parâmetro loop fará com que o arquivo
de som seja executado em loop contínuo.
f) Falso. A função install_keyboard não usa parâmetro algum.
g) Verdadeiro.
h) Falso. Um programa em Allegro só pode ter 16 timers em execução ao mesmo
tempo.
i) Falso. Essa função é a função unload_datafile. A função destroy_datafile não é definida pelo
Allegro.
E.3
a) set_gfx_mode( GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0 );
d) if ( key[KEY_SPACE] ) number = 0;
g) load_datafile( "datafile.dat" );
E.4
a) A variável bmp deveria ser declarada como um ponteiro para um BITMAP. Todas as
funções de bitmap do Allegro ou usam um ponteiro como parâmetro ou retornam
um ponteiro. Um BITMAP que não é um ponteiro é basicamente inútil.
b) O Allegro não define um ―driver mágico‖ WINDOWED. Use o ―driver mágico‖
GFX_AUTODETECT_WINDOWED em seu lugar.
Exercícios
E.5 (Movendo uma imagem com as teclas de seta) Escreva um programa que desenha o
bitmap ball.bmp no centro da tela. Quando o usuário pressiona uma das teclas de seta, o
bitmap deve se mover dez pixels nessa direção.
E.6 (Movendo uma imagem com as teclas de seta) Modifique o programa do Exercício
E.5 de modo que a bola só se mova uma vez para cada vez que uma tecla de seta é
pressionada. Se o usuário segurar uma tecla de seta, a bola deve se mover uma vez e depois
parar até que o usuário solte e pressione a tecla novamente.
E.7 (Movendo uma imagem com as teclas de seta) Modifique o programa do Exercício
E.5 de modo que, se o usuário segurar uma tecla de seta, a bola só se mova uma vez a cada
segundo.
E.8 (Terminando o jogo Pong em 21) Modifique o jogo de Pong da Figura E.21 de
modo que, quando o jogador atingir 21 pontos, o jogo termine e mostre uma mensagem que
o jogador da esquerda ou da direita venceu.
E.9 (Movendo a bola mais rápido em um rali longo) Na maioria dos jogos de Pong,
quando um rali entre os dois jogadores dura muito tempo, a bola começa a correr mais, para
impedir um impasse. Modifique o jogo de Pong da Figura E.21 de modo que a velocidade
da bola aumente para cada dez vezes que ela é atingida em um rali. Quando um dos
jogadores fizer um ponto, a bola deverá retornar à sua velocidade original.
E.10 (Alterando as velocidades da raquete) Alguns jogos de Pong também modificam a
velocidade de uma ou ambas as raquetes do jogador em um esforço para manter o jogo
equilibrado. Modifique o jogo de Pong da Figura E.21 de modo que, quando um jogador
tiver uma dianteira de pelo menos 5 pontos, sua raquete comece a diminuir a velocidade.
Quanto maior a dianteira do jogador, mais lenta sua raquete deverá ser. Se a dianteira do
jogador cair para menos de 5 pontos, sua raquete deverá retornar à velocidade normal.
E.11 (Incluindo um recurso de pausa) Os videogames normalmente possuem um recurso
de ―pausa‖, que permite que um jogador interrompa um jogo em andamento e continue mais
tarde. Modifique o jogo de Pong da Figura E.21 de modo que pressionar a tecla P gerencie
uma pausa no jogo e interrompa o movimento da bola e das raquetes. A pausa no jogo
também deve fazer com que a mensagem "PAUSADO" apareça no centro da tela. Se o jogo
estiver pausado, pressionar a tecla R deverá apagar a mensagem "PAUSADO" da tela e retomar
o jogo.
E.12 (Indicando quando a bola atinge uma raquete) Modifique o programa de Pong da
Figura E.21 de modo que, quando a bola quicar em uma parede ou na raquete, a palavra
"BOING!" apareça em azul no ponto onde a bola tocou e depois desapareça. O texto não deverá
simplesmente sumir ele deverá passar gradualmente para branco.
E.13 (Fornecendo opções de velocidade de bola e raquete) Modifique o jogo de Pong da
Figura E.21 de modo que, antes que o jogo comece, um menu apareça na tela para permitir
que os jogadores escolham dentre várias velocidades diferentes de bola e raquete. Isso é
mais difícil do que parece! O Allegro não tem métodos de entrada de texto. Você terá de
encontrar outro método para resolver esse problema.