Burning Down: Fire Effect
Olá galera. Acho que já falei bastante sobre esse efeito aqui. Mesmo assim, vale a pena olhar novamente!!
O efeito de Fogo!!!!
O efeito de fogo é um efeito bem simples de ser implementado, e que tem um resultado bem atraente. Basicamente o que fazemos com ele é pegar um array colocar nele valores aleatórios e ficarmos fazendo cálculos com esses valores.
Como queimar Roma:
Para calcular a cor de um pixel, o que prescisamos fazer é pegar os valores dos 4 pixels vizinhos ( (x+1,y), (x-1,y), (x,y+1) e (x,y-1) ) , somá-los, tirar a média e subtrairmos algum valor para diminuir a vida do pixel.
A idéia é usar um array de bytes (Mapa: array of array of Byte), e trabalharmos com os seus valores de 0..255. Qdo um valor for igual a 0 esse pixel não seria desenhado, e do contrário ele seria plotado na tela.
E se o valor da divisão dos pixels for 0?? Bom, nós teremos então um valor de pixel negativo. Por estranho que pareca, o delphi faz com que os valores retornem para o final do índice, assim, um valor de pixel - 15 será convertido para o valor 240, assim, acabamos tendo a impressão que se forma um rio de mapa na tela. Então, devemos tratar isso manualmente para que valores menores que zero, continuem zero
E a animação? Como o fogo sobe? Bom, isso eh simples, na hora que formos calcular o valor do pixel, vamos devolvê-lo uma linha para cima no array.
Dois arrays ou um só?
A recomendação desse código é usar dois arrays para calcular o fogo, alternando entre eles enquanto se plota os pixels, (faz-se um cálculo em um array, e plota os valores em outro array que será desenhado, depois inverte), isso é desnecessário, pois pode ser feito apenas com um array, dizem, que fazendo assim o fogo fica estranho, mas eu gostei do resultado, e vc vai poder curtir ele com os meus exemplos que vc vai baixar no final desse post ^^.
Calculando as Cores:
Para calcularmos as cores usamos uma paleta indexada de 0..255 (mesmo comprimento do tipo byte
), sendo que nela configuraremos os valores da seguinte maneira:
0: Valor frio ou preto
1: Valor quase totalmente preto
…
255: Valor máximo de calor
Sendo assim, qdo mais alto o valor, mas quente será o nosso fogo, e mais ele demorará para morrer tb.
Não vou esplicar aki como calcular a diferença de cores, pois vc pode achar isso na net, e com o exemplo vem duas boa paletas tb.
A estrutuda das peletas é bem simples:
Type TPalete = Array[0..255] of TColor;
Bom, vc já deve estar imaginando que os valores de cor são em RGB. logo não será mto difícil trabalhar com essas paletas.
Plotando a cor no Array:
Nada difícil de se fazer, simplesmente use:
NovaCor:= ( Mapa[x+1,y] + Mapa[x-1,y] + Mapa[x,y+1] + Mapa[x,y-1] ) / div 4 - Cooling;
if NovaCor < 0 then NovaCor := 0;
Mapa[x,y + 1]:=NovaCor;
O Mapa[x,y + 1]:=NovaCor, é o que fará a animação do nosso fogo subindo.
O Cooling é um valor inteiro que decrementa o valor do pixel, fazendo assim com que a vida do pixel diminua.
Plotando o Pixel na Tela:
Plotar o pixel na tela vai depender da biblioteca que vc está usando. No meu caso eu estou usando o DelphiX, que tem métodos de desenho mto semelhantes ao Canvas padrão do Delphi, então eu faço assim:
DXDraw.Surface.Canvas.Pixels[x,y] := Paleta[Mapa[x,y]];
Recomendo que faça o desenho dos pixels em uma procedure separada da proedure em que se calcula os valores, isso por questão de organização do código ok?
Bom, creio que não precisa dizer que Paleta é um objeto do tipo TPalete né?
Carregando a Paleta:
Já que tocamos no assunto, devemos criar tb. um tipo:
Type TPaleteFile = File of TPalete;
Com ele podemos tanto salvar e carregar uma paleta com poucas linhas de código:
var MeuArquivo: TPaleteFile; MinhaPaleta:Tpalete;
…
If FileExists(Nome_do_arquivo) then begin
AssignFile(MeuArquivo, Nome_do_arquivo);
Reset(MeuArquivo); // Para ler;
Read(MeuArquivo, MinhaPaleta);
CloseFile(MeuArquivo);
end;
…
Já para salvarmos um arquivo usamos:
var MeuArquivo: TPaleteFile; MinhaPaleta:Tpalete;
…
AssignFile(MeuArquivo, Nome_do_arquivo);
Rewrite(MeuArquivo); // Escrita;
Write(MeuArquivo, MinhaPaleta);
CloseFile(MeuArquivo);
…
Reabastecendo o Fogo:
Logicamente, temos que dar algo para o nosso fogo queimar, então podemos chamar uma procedure, que plota pixels aleatórios em nosso mapa. (De preferência na Ultima linha) , periodicamente, para que assim tenhamso algo pra queimar. E o nosso fogo se tornar contínuo.
Bom, vamos ficar por aki hj, claro que efeitos de fogo não se fazem apenas com isso, podemso usar cooling Map para “modelarmos” o nosso fogo ^^. No exemplo da tocha (que na verdade é uma pira olimpica), eu uso um mapa assim.
Bom, acredito que vc pensou: Com todos estes cálculos, pixels plotanto, isso deve ser lento…
E eh ^^!
Mas, isso pode ser resolvido renderizando as imagens primáriamente antes de mostrar na tela, assim temos frames prontos que não vão mas nos encher com cálculos enormes. Assim como tb. podemos salvar as imagens no disco e carregá-las em nosso jogo para economizarmos tempo de loading, qdo as imagens serão criadas. Isso tb. é ilustrado em meus exemplos, note a diferança da FPS de ambos os desenhos. Note tb. que, usando imagens pré renderizadas, temos um problema, que é acertamos o fluxo dos frames enquanto damos um loop na animação. Esse problema eh ilustrado no exemplo, e vc vai notar o pulo de animação.
Bom eu falei dos exemplos e vc deve estar curioso para vê-los bom aki estão eles:
Bom, lamento por deixar uma explicação tão vaga e confusa, mas o meu tempo é curto, mas, não se preocupem, logo vcs verão mais desse efeito.
VLW!
Leitura Recomendada:
special effects game programming With DirectX
Quem quizer um artigo mais detalhado sobre o efeito de fogo pode ler o meu artigo (Fire and Smoke) na PDJ Zine 2:
Bye o/

fevereiro 6th, 2008 at 7:25 pm
É isso ae, Edmar!
Vamos botar lenha na fogueira!
Seus posts sobre efeitos gráficos estão ficando muito bons e espero que o pessoal que trabalha com Delphi esteja curtindo, já que nós testamos nele e funcionaram todos direitinho.
Sucesso a todos e que o bloggers da PDJ busquem sempre trazer altos conhecimentos para a galera.
Até mais!