Utilizando Sprites e Bitmaps em Delphi sem DirectX

Compartilhar/Favoritos

É um tutorial que demonstra algumas formas de criação de jogos ou animações “suaves” em Delphi de forma simples sem precisar DirectX.

Este é de um grupo de posts muito antigos, de 2002. Vêm do meu antigo site, quando ainda trabalhava com Delphi e tinha um K6-2(!!!!). Bons tempos aqueles…

Provavelmente não serve para muita coisa hoje, mas é legal ver como as coisas eram. Além disso, ainda há gente acessando!

Este pequeno tutorial se destina àqueles que gostariam de fazer animações de bitmaps e sprites (e joguinhos) em Delphi e não têm tempo ou paciência para aprenderem DirectX ou simplesmente não querem usá-lo.

O tutorial é composto por uma série de exemplos que demonstram e descrevem dois métodos diferentes de desenho e movimento de sprites. Este texto serve só como introdução aos exemplos.

Os exemplos foram escritos em Delphi 5.

Para acompanhar o tutorial, você deve pegar os arquivos fonte dos exemplos. Escolha uma das opções:

O tutorial foi desenvolvido em e para Delphi 5.

Comentários

Um problema encontrado pelos programadores quando usam os componentes nativos do Delphi (usando TImage, por exemplo) é que estes não foram desenvolvidos para serem movimentados da forma como os jogos o fazem, mas para ficarem praticamente estáticos no formulário.

Ao movimentar um TImage, por exemplo, a imagem pisca ao ser redesenhada na nova posição. Para ver como fica, veja o Exemplo 1.

O que acontece para que ocorra este efeito? Quando o Delphi muda a posição de qualquer controle em um formulário, ele informa ao Windows que o retângulo onde estava o bitmap deve ser redesenhado, e que deve ser apagado antes. Ou seja, a imagem pisca porque é apagada antes de ser desenhada na nova posição.

A solução, portanto, é óbvia: a área onde está a nova imagem não deve ser apagada antes de desenhá-la. Existem várias formas de fazer isto no Delphi.

Serão apresentadas duas soluções através de alguns programas de exemplo. Na realidade, o tutorial constitui-se destes exemplos. Como foi mencionado, este texto serve somente como introdução ao assunto.

A primeira solução é a mais simples. Entretanto, é extremamente limitada. Só pode ser usada para mover controles TImage não transparentes. Além disso, somente um TImage pode ser movimentado ao mesmo tempo e, para completar, é lenta.

A segunda solução é muito mais interessante. É um pouco mais complicada, mas tem muitas vantagens. Pode-se desenhar sprites (imagens transparentes) de forma muito mais rápida que através do primeiro método. Ela pode também ser usada tranqüilamente para implementar jogos para o Windows usando o Delphi. Claro que, se o assunto é performance, deve-se utilizar DirectX.

Jogos de ação, por exemplo, são viáveis só em resolução 320×240 (com 16 bits de cor) ou em computadores com alta performance de vídeo.

Nos testes, desenhando 100 imagens de 32×32 pixels e 20 de 64×64 pixels, em resolução 640×480 com 16 bis de cor, num computador K6-2 500MHz com placa Blaster Banshee, chegou a 250 frames por segundo. O mesmo teste, em um K6-2 350MHz com placa on-board SiS 530, não passou de 50 FPS.

Métodos

Os métodos são demonstrados e descritos nos exemplos que acompanham este tutorial.

Os exemplos foram pouco testados. Por isso, não me resposabilizo por qualquer dano causado pelos exemplos.

Outra coisa importante: muitos comentários foram retirados de um exemplo para outro. Por isso, caso não souber para que serve algo no código, verifique os exemplos anteriores. Talvez encontre o que quer.

Por último, alguns dos exemplos iniciam a demonstração quando você clicar com o mouse no form. Quando uma tela parada for apresentada, clique com o mouse em cima.

O primeiro método: usando TImage

Quando pensei sobre o problema, imaginei técnicas de uso de back buffers e implementei os exemplos deles. Depois pensei em fazer um exemplo de como era horrível usar o TImage (veja no Exemplo 1). Assim vieram algumas idéias de como fazer com que ele não piscasse e fui testando uma a uma. No fim, cheguei a uma solução muito simples.

Como foi mencionado antes, esta técnica se limita a fazer um TImage se movimentar pelo form sem piscar. Além disso, os bitmaps não podem ser transparentes (olhe a propriedade TImage.Transparent). Por isso, se quiser “algo mais”, veja a outra técnica.

Para saber como este método funciona, você deve abrir o Exemplo 2.

Quando um TImage é movido, o Delphi manda invalidar a área dele. Ao fazer isto, indica que é para apagar a área antes. Quem conhece o Windows sabe que uma área inválida só é apagada e redesenhada quando as mensagens são processadas (no Delphi, Application.ProcessMessages). Por isso, antes de executar Application.ProcessMessages, mando validar novamente a área onde a imagem está. Assim, o Windows deixará a área como está, sem apagá-la.

Só que assim também não desenhamos nossa nova imagem. Por isso, após processar as mensagens, mando invalidar novamente a área da imagem e mando processar as mensagens novamente. Só que desta vez não mando apagar o fundo antes.

O segundo método: back buffer

Este método, demonstrados nos exemplos 3, 4, 5, 6, 7 e 8, utiliza um esquema bem conhecido de quem usa o DirectX: o back buffer.

Um back buffer é uma porção de memória usada para armazenar a imagem que se deseja desenhar antes de ser transferida para o vídeo. Corresponde a uma imagem geralmente com as mesmas dimensões da área que se deseja desenhar (a área inteira). Em um jogo em tela inteira, por exemplo, corresponde às dimensões do modo de vídeo.

Antes de desenhar um quadro (frame), temos que apagar o buffer (pintar da cor que será a cor de fundo), e desenhar a(s) imagem(s) nele. Ao final desta fase, basta transferir todo o buffer para a janela.

Como é uma “tela” em memória, não aparece no vídeo e pode ser apagada, desenhada, processada, etc, etc, etc sem que ninguém veja. Quando estiver pronta, basta passar para o vídeo.

Além disso, o Delphi nos ajuda bastante ao disponibilizar o objeto TBitmap. Como deve saber, o TBitmap é um objeto que mantém uma imagem e uma palette. A imagem pode ser carregada de arquivos BMP. O próprio TImage utiliza um objeto destes quando sua imagem é carregada de BMP.

Um TBitmap pode ser criado sem nenhuma imagem carregada de arquivo. Basta executar o constructor Create e atribuir valores às propriedades Width e Height. É assim que criamos nosso back buffer.

Abaixo há explicações simples sobre cada um dos exemplos que demonstram back buffers. As explicações completas estão em comentários nos próprios exemplos.

Exemplo 3

Este exemplo é o primeiro a utilizar o esquema do back buffer e não implementa ainda transparência. Faz o mesmo que o Exemplo 2 utilizando o back buffer.

Exemplo 4

É o mesmo que o anterior, só que desenha vários bitmaps ao mesmo tempo, ainda sem transparência. Além disso, os bitmaps são animados (graças ao “donut.bmp” que vem com o DirectX SDK).

Exemplo 5

O mesmo que o anterior, só que com transparência. É bom mencionar que não é blend. Na transparência, alguns pontos são desenhados e outros não. No blend, você pode determinar o grau de transparência da imagem ou de pontos dela, tornando-a “semitransparente”.

Exemplo 6

Decidi incrementar o anterior incluindo, além dos “donuts”, carrinhos (que também foram “generosamente cedidos” pela Microsoft) pulando na tela. Incluí, também, uma estatística no número de frames por segundo e uma maneira de aumentar e diminuir o número de objetos na tela.

Obs: mudar o número de objetos só tem efeito se você parar a animação de recomeçá-la.

Exemplo 7

É a implementação do exemplo anterior com mudança de modo de vídeo. Você pode escolher o modo que deseja mudando as constantes CResolWidth e CResolHeight.
O código mudou bastante. Nos comentários estão as explicações do porque disto.

Exemplo 8

Este é o mais interessante. Demonstra um pouco de como fazer um joguinho com as técnicas de utilização de back buffer.

Além disso, mostra como usar o teclado sem o DirectX. Use as setas para mover o carrinho (ou nave, se quiser).

O código não está comentado adequadamente. Este é um desafio…

Boa sorte…

You may also like...

1 Response

Deixe uma resposta

O seu endereço de email não será publicado Campos obrigatórios são marcados *

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Translate »