Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

GDP - Aulão de Allegro 2011-2

No description
by

Jefferson Bandeira da Silva

on 18 February 2013

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of GDP - Aulão de Allegro 2011-2

Aula de Suporte de Allegro 4.2
"2012/2" Por Jefferson Bandeira
www.dcc.ufrj.br/~jeffersonbandeira Uma visão geral do que será ensinado Prog. Jogos 2D I Allegro - Uma biblioteca para Game Dev.

Técnicas de Anti-Flickering

Temporização

Animação em 2D Allegro - Conhecimentos Básicos O que é Allegro? Onde Baixar Como Instalar Compilando seu programa usando a Biblioteca Allegro Allegro é uma biblioteca para desenvolvimento de jogos, originalmente produzida para ser utilizada na plataforma ATARI ST, e que evoluiu e atualmente se tornou uma grande biblioteca para desenvolvimento de jogos 2D, contando com tudo, desde rotinas básicas como gráficos, som, entrada/saída e até coisas mais complexas como matemática tridimensional e transformações em imagens.

Atualmente se encontra na versão 5.0.3. Curiosidade Uma das possiveis explicações para o nome Allegro é ser um acrônimo recursivo para : Allegro
Low
LEvel
Game
ROutines Na GDP usamos a versão 4.2.3 da biblioteca Allegro, ela pode ser encontrada para download no link abaixo : http://www.allegro.cc/files/?v=4.2 No site acima, você terá que baixar 2 arquivos, o primeiro é "Allegro 4.2.3 for MinGW", o segundo "Tools & Examples".
Os links também seguem abaixo para aqueles que forem preguiçosos. =P 1 ) http://migre.me/5kSKv
2 ) http://migre.me/5kSLj A Instação da biblioteca é bem simples.
Abra o arquivo "allegro-mingw-4.2.3.zip" em algum programa de descompactação.
Dentro da pasta de mesmo nome, existirao outras 3 pastas, "include" "lib" e "bin". Para instalar basta copiar essas 3 pastas para dentro da pasta do seu compilador, apertando em "sim" quando o Windows perguntar sobre "sobrescrever pasta". Na compilação, a única coisa que deve ser feita a mais é adicionar uma flag de compilação ao final:

-lalleg Allegro - Rotinas de Inicialização Inicialização? What's Next? Antes de podermos usar qualquer uma das funções e funcionalidades da biblioteca Allegro, temos que antes aprender como dizer ao nosso computador que queremos usar coisas da Allegro.

Assim como em C, quando era necessário usar a função "sqrt(float)" tinhamos que inserir no começo do programa a linha "#include <math.h>", para usar as funções da Allegro temos que adicionar a linha "#include <allegro.h>". Após incluido o header da biblioteca temos que chamar as rotinas de inicialização da biblioteca, são elas : allegro_init(); install_keyboard(); install_mouse(); install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL); set_window_title(char* title); set_color_depth(int color_depth); set_gfx_mode(int mode, int width, int height, int v_width, int v_height); Inicia o core da biblioteca allegro. Instala as rotinas para uso do teclado. Instala as rotinas para uso do mouse. Instala as rotinas para uso de Som. Define o titulo da janela. Define o número de bits de cor da janela ( 1, 8, 16, 24, 32 ( 24+Alpha ) ). Define as opções da janela do jogo.
int mode : Pode ser GFX_AUTODETECT_WINDOWED ou GFX_AUTODETECT_FULLSCREEN
int width & int height : Largura e Altura da janela em pixels, respectivamente.
int v_width & int v_height : Largura e Altura da janela virtual. Desafio! A biblioteca Allegro por padrão não aceita caracteres fora do sistema ASCII, porém, existe uma chamada de função que acaba com esse problema. Procurem na documentação da biblioteca como resolver esse problema e resolvam! E por último... Terminado o programa, devemos desinstalar tudo que instalamos no começo, as funções para isso são : allegro_exit(); remove_keyboard(); remove_mouse(); remove_sound(); Desliga o core da biblioteca allegro. Desinstala as rotinas para uso do teclado. Desinstala as rotinas para uso do mouse. Desinstala as rotinas para uso de Som. Atenção : A ordem é importante! allegro_exit() so pode ser chamada depois que todas as outras forem! Um Exemplo de programa base em Allegro. END_OF_MAIN() Essa macro deve ser colocada ao final da sua função main(), esquecer de coloca-lá gera erros estranhos relacionados a WinMain@16. Da pra perceber que esse código está bem feio, existem várias melhorias que podem ser feitas para melhorar a visibilidade e a reutilização desse código.

Dentre elas, que tal englobar todas as funções de inicialização em uma função bool init()? Por que bool? Essa função deve ter parâmetros?

E que tal englobar as funções de encerramento em uma função void closing()?

E quem sabe não seria legal mudar aqueles números e bota-los como constantes definidas no pré-processamento?

Fica ai então mais um desafio, começar a montar o seu primeiro código esqueleto para jogos em Allegro. =) Allegro - Rotinas de Desenho Rotinas de Desenho - Intro Uma das melhores coisas da biblioteca Allegro é sua capacidade de desenhar primitivas básicas sem necessitar de esforço algum da parte do programador.

Essa simples diferença traz muitas vantagens, uma delas é permitir ao programador fazer efeitos legais via programação sem a necessidade constante de um designer gráfico ao lado.

Outra vantagem é permitir um feedback visual rápido para seus testes nos jogos. Teve uma idéia muito boa de um jogo simples e quer testar como seria a jogabilidade? Faça um esboço do seu jogo com primitivas simples e sinta como ficaria, se gostou da idéia , invista nela! Rotinas de Desenho - Intro II Antes de partirmos para as funções de desenho em si, temos que dar uma rápida passada pelo sistema de cores que a Allegro usa.


No sistema de cores da biblioteca Allegro, uma cor é representada por um int. Como todos sabem , um int possui 32 bits, esses 32 bits são divididos em 4 pedaços, como na figura abaixo. Cada um desses pedaços é a intensidade de uma das componentes da cor, Red, Green, Blue e Alpha. Como são 8 bits pra cada um, os números variam de 0 a 255, 0 representando "sem intensidade" e 255 representando "o mais intenso possivel".

Alguns exemplos de cores seguem na imagem abaixo ( Apenas componentes R, G e B, Alpha será explicado mais tarde). E eu com isso? Como veremos mais a frente, todas as funções de desenho recebem um parâmetro "int color", esse parametro segue o formato explicado acima, existem varias formas de pegar essas cores em Allegro, abaixo explicarei duas que são as mais simples. Modo 1 Uma das formas de se conseguir o valor de uma cor é usando uma das várias funções oferecidas pela Allegro que tem o formato int make*col*( parâmetros ). Onde o primeiro * indica com ou sem alpha, e o segundo * indica o numero de bits da cor, ex.:

int makecol32(int R, int G, int B ) - Retorna uma cor 32 bits com os fatores R, G, B.
int makeacol32(int R, int G, int B, int A) - Retorna uma cor 32 bits com os fatores R, G, B e A.
int makecol(int R, int G, int B) - Retorna uma cor no sistema de cor atual do programa com os fatores R, G e B.
int makeacol(int R, int G, int B, int A) - Mesmo que makecol, porém considerando o fator A.

Na dúvida sobre qual usar, use makecol() ou makeacol() caso queira alpha.

Além disso, é possivel pegar cada um dos componentes de uma cor com as funções int get*(int color), onde * pode ser r, g , b ou a. Modo II O Segundo modo de criar uma cor é um pouco mais hardcore do que o primeiro, e consiste em escrever a cor diretamente como um Hexadecimal, no formato 0xRRGGBB. Ex.:

Vermelho = 0xFF0000
Azul = 0x0000FF
Amarelo = 0x00FFFF

0's a esquerda podem ser omitidos, logo, as 3 cores acima podem ser escritas como :

Vermelho = 0xFF0000
Azul = 0xFF
Amarelo = 0xFFFF

E não, não é muito recomendado fazer isso. =P Desenho de Primitivas As funções de desenho de primitivas da Allegro seguem o seguinte padrão :
void NomeDaFunção( BITMAP* bmp, <Parâmetros específicos> , int color);

Por enquanto, vamos ignorar o que é o parametro BITMAP* bmp, e vamos usar uma variável global disponivel na Allegro chamada "screen", pense nela como a tela do seu programa. Primitivas simples Linhas void line(screen, int x1, int y1, int x2, int y2, int color);
Desenha uma linha do ponto (x1,y1) até (x2,y2).

void hline(screen, int x1, int y, int x2, int color);
Desenha uma linha horizontal do ponto (x1,y) até (x2,y).

void vline(screen, int x, int y1, int y2, int color);
Desenha uma linha vertical do ponto (x,y1) até (x,y2). Circulo void circle(screen, int x, int y, int radius, int color);
Desenha uma circunferência de raio radius, centrada em (x,y).

void circlefill(screen, int x, int y, int radius, int color);
Desenha um circulo de raio radius centrado em (x,y). Rect void rect(screen, int x1, int y1, int x2, int y2, int color);
Desenha o contorno de um retangulo que vai do ponto (x1,y1) até (x2,y2).

void rectfill(screen, int x1, int y1, int x2, int y2, int color);
Desenha o retangulo que vai do ponto (x1,y1) até (x2,y2). Triangulo void triangle(screen, int x1, int y1, int x2, int y2, int x3, int y3 int color);
Desenha o triangulo preenchido formado pelos pontos (x1,y1), (x2,y2) e (x3, y3). Primitivas não tao simples Elipse void ellipse(screen, int x, int y, int rx, int ry, int color);
Desenha o contorno da elipse centrada em (x,y), com raio em x igual a rx e raio em Y igual a ry.

void ellipsefill(screen, int x, int y, int rx, int ry, int color);
Desenha uma elipse centrada em (x,y), com raio em X igual a rx e raio em Y igual a ry. Polygon void polygon(screen, int n, int* points, int color);
Desenha um polígono de n lados.
Os vértices do polígono devem ser colocados em um vetor e passado pelo parâmetro points. Um exemplo será mostrado a seguir. Exemplo.: Esse código gera isso... Rotinas de Manipulação de Imagem
Intro Até agora sabemos como desenhar primitivas básicas na tela e texto, porém, nenhum jogo que se preze vive apenas de primitivas, grande parte do apelo de um jogo consiste exatamente em sua beleza gráfica, e para isso precisamos de algum jeito de manipular imagens dentro do nosso jogo.

Para isso, a Allegro nos oferece um leque imenso de possibilidades para leitura/escrita e manipulação de imagens em varios formatos, dentre eles BMP, TGA, PCX e LBM, também é possivel carregar arquivos PNG e JPEG usando extensões existentes. Rotinas de Manipulação de Imagem
Overview do tipo BITMAP* Anteriormente na parte de primitivas e na parte de output, vimos que o primeiro parâmetro das funções era do tipo BITMAP*, mas o que é esse tipo?

O Tipo BITMAP* representa uma imagem. Ponto.

A Allegro oferece também várias funções para manipulação de váriaveis do tipo BITMAP*, que serão explicadas mais a frente.

Antes de continuar, porém, temos que perceber uma coisa, a variável "screen" , que representa a sua tela do jogo, É um BITMAP*, portanto, qualquer operação pode ser feita nela, ou a partir dela também.

Muita atenção na palavra "pode", apesar de possível NÃO é recomendado fazer alterações direto na váriavel screen, pois as mudanças feitas a ela ficam disponiveis imediatamente ao usuário que está na frente do monitor. Isso pode gerar um problema que veremos mais a frente, chamado Flickering. Allegro - Rotinas de Input/Output Rotinas de Input / Output
Intro Uma das principais caracteristicas que diferenciam um jogo de um filme é a interatividade com o usuário.

Para permitir essa interatividade a Allegro nos oferece rotinas simples e efetivas para controle de entrada e saída de dados via teclado e mouse. Rotinas de Input / Output
O Mouse O controle do mouse pela Allegro é feito a partir de algumas variáveis globais e algumas funções, são elas : Váriavel contendo a posição X em pixels do mouse em relação ao canto superior esquerdo. int mouse_x; Váriavel contendo a posição Y em pixels do mouse em relação ao canto superior esquerdo. int mouse_y; Váriavel contendo a posição atual da rodinha do mouse. int mouse_z; Váriavel contendo uma bitmask que indica quais botões do mouse estão pressionados, para saber um botao especifico, basta fazer um & bit a bit com a mascara do botao desejado. Ex.:
1 - Botao Esquerdo
2 - Botao Direito
4 - Botao do meio
if( mouse_b & 1) { // Botao esquerdo apertado. } int mouse_b; Posiciona o mouse na posição (x,y) da tela em relação ao canto superior esquerdo. void position_mouse(int x, int y); Escreve em x e em y o quanto o mouse andou desde a ultima chamada a essa mesma função. void get_mouse_mickeys(int* x, int* y); Rotinas de Input / Output
O Teclado O controle do teclado, por sua vez, consegue ser mais simples do que o do mouse, usando apenas um vetor e uma gama imensa de constantes. Segue abaixo: Vetor que indica o estado atual de uma tecla, se o valor for 0, a tecla está solta, diferente de 0 a tecla está pressionada char key[KEY_MAX] Constantes KEY_A ... KEY_Z,
KEY_0 ... KEY_9,
KEY_0_PAD ... KEY_9_PAD,
KEY_F1 ... KEY_F12,

KEY_ESC, KEY_TILDE, KEY_MINUS, KEY_EQUALS,
KEY_BACKSPACE, KEY_TAB, KEY_OPENBRACE, KEY_CLOSEBRACE,
KEY_ENTER, KEY_COLON, KEY_QUOTE, KEY_BACKSLASH,
KEY_BACKSLASH2, KEY_COMMA, KEY_STOP, KEY_SLASH,
KEY_SPACE,

KEY_INSERT, KEY_DEL, KEY_HOME, KEY_END, KEY_PGUP,
KEY_PGDN, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN,

KEY_SLASH_PAD, KEY_ASTERISK, KEY_MINUS_PAD,
KEY_PLUS_PAD, KEY_DEL_PAD, KEY_ENTER_PAD,

KEY_PRTSCR, KEY_PAUSE,

KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT,
KEY_AT, KEY_CIRCUMFLEX, KEY_COLON2, KEY_KANJI,

KEY_LSHIFT, KEY_RSHIFT,
KEY_LCONTROL, KEY_RCONTROL,
KEY_ALT, KEY_ALTGR,
KEY_LWIN, KEY_RWIN, KEY_MENU,
KEY_SCRLOCK, KEY_NUMLOCK, KEY_CAPSLOCK

KEY_EQUALS_PAD, KEY_BACKQUOTE, KEY_SEMICOLON, KEY_COMMAND Rotinas de Input / Output
Output Intro Algo muito útil e necessário muitas vezes, principalmente na hora de debugar o seu programa, é ter a capacidade de obter um output do seu programa.
E não só para debug, coisas informativas no seu jogo, como o score atual do player, por exemplo, não podem ser feitas bonitas por um designer pois são coisas que mudam constantemente, para esse tipo de coisa a Allegro nos oferece rotinas para desenhar textos variados na tela. Rotinas de Input / Output
Output Routines O output na Allegro é feito a partir de 2 tipos diferentes de funções, e um tipo especial, o tipo FONT*.

O tipo FONT* será explicado com detalhes no Treinamento de Programação de Jogos 2D II, por agora usaremos uma fonte padrão da Allegro, a variável global chamada "font". As rotinas do tipo textout_format_ex servem para desenhar na tela uma string sem formatação, na posição (x,y), com cor de texto color, e com o fundo do texto de cor bg. Caso BG seja -1 o fundo será transparente. void textout_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg); As funções para output de texto seguem a seguir : void textout_centre_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg); void textout_right_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg); void textout_justify_ex(BITMAP *bmp, const FONT *f, const char *s, int x, int y, int color, int bg); As rotinas do tipo textprintf_format_ex servem para desenhar na tela uma string COM formatação, na posição (x,y), com cor de texto color, e com o fundo do texto de cor bg. Caso BG seja -1 o fundo será transparente.
Essas funções funcionam parecido com o printf padrão do C, caso vc queira escrever um int, seria .:
textprintf_ex(screen, font, 10, 10, makecol(255,255,255), -1, "Número : %d", score); ( Supondo que "score" é uma variável int ). void textprintf_ex(BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ...); void textprintf_centre_ex(BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ...) void textprintf_right_ex(BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ...); void textprintf_justify_ex( BITMAP *bmp, const FONT *f, int x, int y, int color, int bg, const char *fmt, ... ); int text_length( const FONT* f, const char* str);
int text_height( const FONT* f, const char* str); As duas funções acima dizem a largura e altura de uma string str em uma fonte f.
Ex.: text_lenght( font, "Oi, eu sou o Goku.") retornaria 18*8 pixels, pois a fonte padrão do allegro é uma fonte mono-espaçada onde cada caracter tem 8 pixels de largura e 8 pixels de altura. Afinal de contas... Eu pelo menos prefiro o jogo a esquerda. =P O tipo BITMAP é definido internamente como uma struct, e como tal existem coisas interessantes para se saber.

Duas delas são os parametros w e h, que obviamente querem dizer largura e altura do BITMAP. ATENÇÃO! Sempre trabalharemos com BITMAP*, nunca com BITMAP, portanto ao acessar esses parâmetros lembrem que em ponteiro pra struct usamos -> e não . ! Técnicas de Anti-Flickering Flicker - O que é isso? Agora falaremos sobre Flicker, o que é esse efeito e como contorná-lo. Flicker - E agora? Flicker é um efeito incomodo para os olhos que acontecem quando não existe uma consistência na atualização constante de uma imagem.

Por exemplo, se no seu jogo vc ao final de cada loop for feita uma chamada a clear_bitmap(screen), e todos os seus desenhos forem feitos tambem em cima da variavel screen, ocorrerá o flicker. Por que?

Como foi dito anteriormente, as mudanças feitas direto na variavel screen são mostradas instantaneamente para o usuário, então no breve momento que o seu programa deu o clear_bitmap(screen), a tela ficou preta e logo em seguida começaram os desenhos do proximo loop de interação do seu jogo, isso gera um efeito de "tela piscando", esse é o flicker. Ainda existem algumas outras funções de utilidade para váriaveis BITMAP*, são elas : void clear_bitmap( BITMAP* bmp ); Rotinas de Manipulação de Imagem
Brincando com o tipo BITMAP* Agora vamos ver como usar o tipo BITMAP*, dividirei esse assunto em 4 tópicos :

Criação
Carregamento
Drawing
Destruição O tipo BITMAP é definido internamente como uma struct, e como tal existem coisas interessantes para se saber.

Duas delas são os parametros w e h, que obviamente querem dizer largura e altura do BITMAP. ATENÇÃO! Sempre trabalharemos com BITMAP*, nunca com BITMAP, portanto ao acessar esses parâmetros lembrem que em ponteiro pra struct usamos -> e não . ! Criação de BITMAP* Caso você queira criar um BITMAP* para desenhar em cima ou qualquer coisa do gênero, existem funções específicas pra isso, são elas : BITMAP* create_bitmap(int width, int height);

BITMAP* create_video_bitmap(int width, int height); A primeira função deve ser usada a maioria do tempo, e gera um bitmap em memória comum com width X height de tamanho.

A segunda função será usada mais a frente nesse treinamento quando falarmos de anti-flickering, ela gera um BITMAP* em memória de vídeo, que é especializada para ser mostrada na tela. ATENÇÃO! Não é garantido que a função consiga criar um BITMAP*, portanto sempre que for criado um BITMAP*, VERIFIQUE SE FOI CRIADO DE FATO ( Teste se o ponteiro retornado não é nulo ) Carregamento de imagens do disco Aprendemos a criar váriaveis BITMAP* do 0, mas como fazer para carregar aquela imagem hiper-legal que o seu amigo designer fez pro personagem principal do seu jogo de vampiros?? A Allegro nos permite fazer isso com uma única função : *PAUSA DRAMÁTICA* BITMAP* load_bitmap(const char* filename, RGB* pallete); Essa função recebe 2 parâmetros, o primeiro deles é o caminho até a imagem em si, o segundo é a pallete de cores.
Atualmente palletes foram descontinuadas, então geralmente esse segundo parâmetro acaba sendo NULL. =)
A mesma atenção deve ser dado aqui que foi dada no create_bitmap, o carregamento nem sempre é possivel, então sempre verifique se a imagem foi de fato carregada.
Essa função carrega todos os tipos de imagem suportado pela Allegro: BMP, LBM, PCX, e TGA. Desenho de imagens Agora que sabemos como carregar imagens, falta apenas aprender como fazer essas imagens aparecerem na tela. Para isso, temos mais um leque de funções para nos ajudar. São basicamente 2 tipos de funções, as funções blit e as funções draw. As funções blit fazem uma cópia em bloco de um pedaço do BITMAP* origem em cima de uma posição no BITMAP* destino, copiando cada pixel exatamente como era na imagem original. As funções draw fazem uma cópia do BITMAP* origem em cima de uma posição no BITMAP* destino, porém, essa cópia considera "transparência", onde os pixels com a cor (255, 0, 255) são considerados transparentes e não são desenhados. Funções estilo BLIT void blit(BITMAP *src, BITMAP *dst, int sx, int sy, int dx, int dy, int w, int h); Copia o pedaço do BITMAP* src contido dentro do retangulo (sx, sy) (sx+w, sy+h) para a posição (dx, dy) do BITMAP* dst. void masked_blit(BITMAP *src, BITMAP *dst, int sx, int sy, int dx, int dy, int w, int h); Copia o pedaço do BITMAP* src contido dentro do retangulo (sx, sy) (sx+w, sy+h) para a posição (dx, dy) do BITMAP* dst. Essa função considera os pixels (255,0,255) como transparente, portanto funciona parecido com a função draw_sprite. SRC DST DST SRC DST DST Funções estilo DRAW void draw_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y); Desenha o BITMAP* sprite inteiro na posição (x,y) do BITMAP* bmp, pixels (255,0,255) não são desenhados void stretch_sprite(BITMAP *bmp, BITMAP *sprite, int x, int y, int w, int h); Desenha o BITMAP* sprite inteiro na posição (x,y) do BITMAP* bmp, pixels (255,0,255) não são desenhados. É dado também um resize para que o BITMAP* sprite fique com w de largura e h de altura. void draw_sprite_*_flip(BITMAP *bmp, BITMAP *sprite, int x, int y); Desenha o BITMAP* sprite inteiro na posição (x,y) do BITMAP* bmp, pixels (255,0,255) não são desenhados.
Caso seja colocado v no lugar do *, a imagem é espelhada verticalmente.
Caso seja colocado h no lugar do *, a imagem é espelhada horizontalmente.
Caso seja colocado vh no lugar do *, a imagem é espelhada horizontalmente e verticalmente. Normal VFlip HFlip VHflip Destruição de BITMAP* Assim como todas as outras váriaveis pointer, devemos destruir as váriaveis BITMAP* após terminarmos de usá-las. A destruição é feita com uma chamada de função : void destroy_bitmap( BITMAP* bmp ); void clear_to_color( BITMAP* bmp, int color ); int getpixel( BITMAP* bmp, int x, int y); void putpixel( BITMAP* bmp, int x, int y, int color ); Preenche o BITMAP* bmp com a cor preta. Preenche o BITMAP* bmp com a cor color Muda a cor do pixel (x,y) do BITMAP* bmp para color. Retorna a cor do pixel (x,y) do BITMAP* bmp. Então, sabemos agora o que é o flicker e qual a sua causa, então, como resolver isso? A resposta pra essa pergunta é : De inúmeras formas.

Nesse treinamento iremos falar de apenas 3 delas, que são as mais usadas atualmente, são elas :

Double Buffering
Page Flipping
Triple Buffering

Cada uma tem suas vantagens e desvantagens, que serão explicadas em detalhes. Double Buffering A técnica chamada de double buffering tem um conceito muito simples. Como o flicker é causado por diversas modificações por loop na tela do jogo, tudo o que temos que fazer é minimizar essas mudanças pra que só seja necessário fazer uma atualização na tela por loop, e para isso usamos um BITMAP* auxiliar do tamanho da tela original que chamaremos de buffer. Esse buffer vai ser onde realizaremos todas as operações de desenho no nosso jogo, e ao final do loop daremos um blit desse buffer para a tela do jogo, limparemos o buffer e começaremos outro loop.

Dessa forma é apenas realizada uma operação de atualização da tela por loop, ao final dele, e isso acaba com o flicker. Vantagens Simples de ser feito.
Simples de ser entendido.
Nao requer memoria de video.
Gasta apenas mais um BITMAP*. Desvantagens Devido a limitação de hardware, não funciona muito bem para fazer side-scrolling. Page Flipping. O Page flipping é uma técnica de anti-flicker que usa um conceito parecido com o double buffer, com uma leve diferença.

Ao invés de desenharmos em um buffer auxiliar, nós teremos 2 "telas" no nosso jogo, chamaremos de T1 e T2. Essas telas são variaveis BITMAP* criadas com a função create_video_bitmap();

Quando a tela T1 estiver sendo mostrada, desenharemos na tela T2, quando a tela T2 estiver sendo mostrada, desenharemos na tela T1.

Um dos pontos positivos dessa forma de agir é que por não estarmos nos prendendo ao blit no final de cada loop, acaba se tornando um pouco mais eficiente, pois ja estamos desenhando aonde será a tela apresentada ao usuário. Isso também elimina o problema que o double buffering gera com side-scrolling. Vantagens Altamente eficiente.
Sem problemas com side-scrolling.
Razoavelmente simples de implementar Desvantagens Gasta o dobro de memoria do double-buffering.
Necessita de memória de video.
Não é muito eficiente quando são feitas muitas operações de desenho devido a VRAM. Triple-Buffering O Triple-Buffering é o melhor dos 3 tipos de anti-flicker, porém o mais custoso. O Triple-Buffering é muito parecido com o Double-buffering, porém ele elimina uma ineficiencia existente no double-buffering. Durante uma operação de blit, nenhum dos dois BITMAP* envolvidos na operação podem ser modificados até que a cópia seja completada.

Isso gera muitas vezes um atraso de milisegundos onde o seu jogo tem que esperar esse blit acontecer, pois com o buffer e a screen travados pelo blit o programa fica sem onde desenhar.

O Triple buffering usa 3 BITMAP* de video para contornar esse problema.
Chamaremos os 3 BITMAP* de P1, P2 e P3.

Se P1 for a tela que está sendo mostrada no momento, e fomos mostrar a P2 a seguir, P1 e P2 ficam travadas, para não perder tempo, o triple-buferring começa a desenhar no BITMAP* P3. Ao final do loop, ocorre a troca entre P2 e P3, ambos travam e começa o desenho em P1.... and so it goes. Vantagens Desvantagens O mais eficiente de todos os métodos de anti-flicker.
Não apresenta as falhas que o Double-Buffering e o Page Flipping apresentam
Processador e VGA podem trabalhar a velocidade máxima possivel. Complicado de ser feito.
Complicado de se entender.
Depende de capacidades específicas do hardware.
Nem todo computador suporta =(. Allegro - Rotinas de BITMAP Allegro - Temporização Temporização
Intro Outro assunto muito importante na hora de se desenvolver jogos é a temporização.
Se for montado um protótipo de jogo com tudo que foi ensinado até agora nessas aulas ficará perceptivel que ainda falta alguma coisa crucial para seu jogo ficar jogável.
Essa coisa é exatamente a temporização.
Nessa aula veremos o quão importante é a temporização e que a Allegro oferece várias soluções pra realiza-la. Temporização
Por que é importante? O que a temporização tem de tão importante? Segue uma lista : Sem temporização a velocidade dos jogos fica extremamente dependente do hardware do computador, ficando ultra-veloz em um computador top de linha, e extremamente lento em um computador muito antigo.
Muitas vezes em seu jogo é necessario algum tipo de controle de tempo, por exemplo worms, onde as granadas explodiam depois de 1-5 segundos.
As animações das sprites do seu jogo requerem temporização para ficarem bonitas. As pessoas mais céticas devem estar pensando : "Mas não é melhor que meu Jogo rode na maior velocidade possivel?" Afinal, esse é um pensamento totalmente válido.
Porém, a carga gráfica e de processamento que o seu jogo utiliza não é algo constante, é totalmente instável, deixar o jogo sem temporização significaria que em certos momentos de calmaria seu jogo poderia rodar a 500+ FPS, e em momentos de carga pesada poderia cair para 30+, essa mudança de 500 para 30 é algo muito brusco e incômodo ao usuário final, por isso que quando fazemos um jogo, geralmente limitamos o FPS máximo do nosso jogo, de forma que mesmo em momentos calmos o FPS continue em um número constante e conhecido ao programador ( Geralmente 30, 60 ou 90 ).
Note que a temporização serve pura e simplesmente como um limite superior para truncar a capacidade do computador. Não a nada que possamos fazer para melhorar o FPS de um computador com hardware inferior, infelizmente. FPS ( Frames per Second ) : Número de vezes que a tela do seu jogo é atualizada por segundo. Temporização em Allegro
How To? Ok, vimos o quão importante é a temporização em jogos, agora como fazer essa temporização em Allegro?
A Allegro oferece uma API paratrabalhar com funções temporizadas, e ela funciona chamando uma função definida pelo usuário em um certo intervalo de tempo, que também é definido pelo usuário.

E como fazer isso? Allegro - Funções de Temporização int install_int_ex(void (*proc)(), int speed); Essa função instala um timer usando a função proc passada por parametro, executando essa função a cada "speed" Ms. Para facilitar no cálculo do tempo, use a macro BPS_TO_TIMER( fps ), onde fps é o número de vezes que quer que a função seja executada cada segundo.
Ex .: install_int_ex( my_func, BPS_TO_TIMER( 60 ) ); fará a função my_func ser chamada a 60 vezes por segundo. int remove_int(void (*proc)()); Desinstala um timer criado com a função install_int_ex na função proc. Detalhes, Detalhes, Detalhes... Obviamente não poderia ser tão simples assim. =)
Existem pequenos detalhes importantes que devem ser levados em conta na hora de fazer temporização. 1 - Funções que servirão como timers tem uma série de restrições Funções timers não devem usar muitas ( de preferencia nenhuma ) variável da pilha, não devem fazer nenhuma chamada ao Sistema Operacional ( exit() e system() por exemplo ), não devem usar funções da biblioteca padrão do C ou qualquer tipo de aritmética de ponto flutuante. Além disso as funções timers PRECISAM executar extremamente rapido. 11 - Toda função e váriavel utilizada na temporização deve ser travada usando macros da Allegro As macros são : LOCK_VARIABLE( var ) e LOCK_FUNCTION( func ). Ficará mais claro no exemplo do próximo slide. Além disso variáveis devem ser do tipo volatile para permitir alteraçao de fora do programa original delas. ( As funções são chamadas pelo S.O. ) 111 - O programador deve indicar onde termina a função que será temporizada Isso é feito usando a macro END_OF_FUNCTION(). 1111 - O Número de funções timers deve ser o mínimo necessário! A Allegro só pode disponibilizar 16 timers ao todo, e vários pedaços da própria biblioteca ja ocupam alguns desses timers. Temporização em Allegro
How to part 11 Todas essas restrições nos fazem pensar o que nos sobra pra fazer e como usar isso nos nossos jogos.
A verdade é, para fazer uma temporização eficiente só precisamos de uma função temporizada que realize apenas um comando, se quisermos fazer um contador de FPS pro nosso jogo, precisamos de mais uma que realizará 2 comandos. Para poder controlar o desenho dos frames no nosso jogo precisamos apenas saber se já é hora ou não de desenhar o próximo frame. Suponha que temos uma variavel chamada "counter" que conta o número teórico de frames que deveriam ter se passado desde o começo do nosso programa que deveria rodar a 60 FPS ( Ou seja, essa variavel é somada 1 a cada 1.0/FPS segundos ) se desenhamos um frame no momento que essa variável tem o valor 40, não precisamos desenhar outro frame até que essa variável passe a ter o valor 41, 1/60 segundos após o desenho anterior, essa condição nos limita a desenhar no máximo 60 frames por segundo, que é exatamente o que queremos.

Para fazer isso só o que precisamos é uma variável counter que seja incrementada a cada 1.0/60 segundos, e é ai que as funções counter da Allegro entram em jogo. Temporização em Allegro
Código base Temporização em Allegro
How to - Visualização de FPS atual Outra coisa interessante de se saber é qual a taxa de FPS do seu jogo em um certo momento.
A idéia por tras é muito parecida com a idéia do controle de FPS, a cada frame que terminarmos de desenhar no nosso jogo, somaremos 1 a uma variável chamada "frames_desenhados", e dentro de uma função temporizada chamada "calcula_fps" que será executada 1 vez por segundo vemos o valor de "frames_desenhados" e consideramos como a nossa taxa de FPS praquele segundo e a guardamos numa variável "fps_atual". O problema de fazer desse jeito é que o nosso FPS só será atualizado 1 vez por segundo, caso queira uma atualização de FPS mais constante, basta diminuir o intervalo de chamada da função calcula_fps e ajustar de acordo no calculo da variavel "fps_atual".
Ex .: Se a função calcula_fps for chamada a cada 1/4 segundos, basta multiplicarmos por 4 o valor de frames_desenhados. Animação de Sprites
Intro Outra coisa muito importante em jogos é que seus objetos não fiquem estáticos o tempo todo, muita da diversão de jogos é ver o seu personagem andar, correr, bater, matar, pular, dançar e assim vai. Para alcançar tais efeitos, precisamos saber como animar uma imagem em nosso jogo. Técnicas de Animação 2D Algum de vocês ja pensou como é feita uma animação em 2D? Animação de Sprites Animações em 2D são basicamente várias imagens parecidas desenhadas alternadamente na mesma posição, se as imagens forem bem feitas consegue-se passar uma impressão de continuidade ao usuário. Algum de vocês ja pensou como é feita uma animação em 2D? Existem 2 técnicas de animações que podem ser feitos em Allegro.
Animação Vetorial
Animação Controlada Animação de Sprites
Animação Vetorial Animação vetorial consiste em carregar uma série de imagens que formam uma animação sequencialmente em um vetor de BITMAP*, e na hora de desenhar o personagem na tela, desenhamos a imagem usando a variável de temporização como uma das partes do indice desse vetor, isso nos dará uma animação constante e pouco controlada, mas é uma animação. :P

É possivel "controlar" a velocidade dessa animação fazendo certas aritmeticas com a variavel temporizadora ( A qual será chamada de counter ).
Por exemplo, se indexarmos por counter%NUM_IMAGENS o frame mudará a cada novo loop. Se indexarmos fazendo (counter/2)%NUM_IMAGENS, a velocidade é dividida por 2 e mudará o frame a cada 2 loops. Por que? Animação de Sprites
Animação Controlada O Problema da animação vetorial é exatamente a falta de controle, o delay da animação tem que ser constante para todos os frames, e nem sempre queremos isso. Por exemplo, durante uma animação de respirar queremos que o personagem passe 2 frames inspirando e 5 frames expirando. Infelizmente a animação vetorial não nos dá essa liberdade, e é ai que entra a animação controlada. Na animação controlada, além de passar um vetor com as imagens pertencentes a animação tambem devemos passar um vetor com o delay de cada um dos frames da animação. Usaremos tambem duas novas variáveis, frame_atual e delay_atual. Animação de Sprites
Animação Controlada Com essas 4 coisas em mão ( BITMAPs, Delays, frame atual e delay atual ) podemos fazer a animação controlada.

Sempre desenharemos o frame imagens[frame_atual] na tela, após cada desenho do frame, somaremos o delay_atual em 1, se após essa soma o delay_atual for igual ao delays[frame_atual], avançamos um frame e resetamos o delay_atual para 0. ( Avançar um frame : frame_atual = (frame_atual+1)%NUM_FRAMES; )

Desse jeito temos varias liberdades :
Decidir quanto tempo o personagem vai ficar em cada frame.
Decidir em qual frame a animação começa.
Decidir em qual frame a animação termina. Animação de Sprites
Animação Controlada Com essas 4 coisas em mão ( BITMAPs, Delays, frame atual e delay atual ) podemos fazer a animação controlada.

Sempre desenharemos o frame imagens[frame_atual] na tela, após cada desenho do frame, somaremos o delay_atual em 1, se após essa soma o delay_atual for igual ao delays[frame_atual], avançamos um frame e resetamos o delay_atual para 0. ( Avançar um frame : frame_atual = (frame_atual+1)%NUM_FRAMES; )

Desse jeito temos varias liberdades :
Decidir quanto tempo o personagem vai ficar em cada frame.
Decidir em qual frame a animação começa.
Decidir em qual frame a animação termina.

A seguir, um código mostrando a animação controlada. Problemas com esse código :
Muitas variáveis
Caso tivessemos que fazer várias animações com vários objetos diferentes ficariamos afogadas em tantas variaveis.
Temos que inserir todos os delays 1 por 1, não seria bom se tivessemos a opção de colocar um delay DEFAULT?


Tantos problemas nos faz pensar algo óbvio : Por que não criar uma classe "Animation" que cuidará de tudo referente a animação?

E isso fica como exercicio para semana que vem. Divirtam-se :) Epílogo Isso encerra o treinamento de Prog. Jogos 2D I.
Durante esses 3 dias aprendemos sobre o básico necessário para se começar a ter uma aplicação interativa usando a biblioteca para jogos Allegro.

Vale a pena reforçar que somente essas aulas NÃO são suficientes para vocês aprenderem a programar jogos, 80% do aprendizado consiste em TENTAR e ERRAR. Não deixem sentimentos bobos como medo e vergonha atrapalharem vocês durante essa jornada ao conhecimento ( E a diversão, se você for um nerd que nem eu ).

Estudem em casa, treinem e tenham certeza de dar o melhor de si. Pois no final, determinação é o que importa.
Abraços,
Jefferson Bandeira, a.k.a. Perdigão. Epílogo E mais uma vez os guerreiros da horda conseguem derrotar o mal que assombrava Azeroth..... Opa, epílogo errado..... E é isso ai. =)
Full transcript