O SDL – Simple DirectMedia Layer – é um conjunto de bibliotecas desenvolvido para construir aplicações multimídia com imagens, áudio, vídeo e um bom desempenho. Estas aplicações são portáveis entre diversos sistemas operacionais e há implementações em diversas linguagens de programação. Neste post vamos lidar com o mínimo necessário para se criar uma aplicação em C que faz uma animação com imagens.
Configurando o ambiente: Windows
Dev-C++
Para quem utiliza o Dev-C++, é necessário instalar o devpak do SDL disponível em http://devpaks.org/details.php?devpak=12. Após baixar o arquivo, é só adicioná-lo no Dev-C++ no menu Ferramentas>Package Manager>Install
. Após a instalação do devpak, é possível criar um Novo Projeto>Multimedia>SDL
.
Linux
Ubuntu
No Ubuntu basta ter acesso ao suders para dar um:
sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev |
Para compilar os exemplos utilize o seguinte comando
gcc -lSDL -lSDL_image arquivo.c -o executavel |
Primeiro vamos criar uma aplicação mínima que inicia o SDL para checar se sua instalação está correta. Crie a seguinte estrutura:
#include "SDL/SDL.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Init(SDL_INIT_EVERYTHING); SDL_Quit(); } |
Se compilou sem erros, sua instalação está ok. Agora vamos adicionar uma tela aonde vamos fazer tudo acontecer:
#include "SDL/SDL.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Surface *screen; SDL_Init(SDL_INIT_EVERYTHING); screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); SDL_Quit(); } |
Neste ponto vemos que a screen, ou nossa “tela” aparece, mas logo em seguida é finalizada pelo SDL_Quit().
Vamos inserir um laço infinito que vai ficar rodando sem parar, escutando por eventos do teclado. Por enquanto a unica coisa que ele vai responder é ao apertar da tecla ESC, quando irá encerrar o programa:
#include "SDL/SDL.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Surface *screen; SDL_Event event; SDL_Init(SDL_INIT_EVERYTHING); screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); while(1){ if( SDL_PollEvent( &event ) ){ switch(event.type){ case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_ESCAPE: SDL_Quit(); exit(0); break; default: break; } break; default: break; } } } SDL_Quit(); } |
Vamos agora carregar uma imagem do disco em uma variável:
#include "SDL/SDL.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Surface *screen; SDL_Event event; SDL_Init(SDL_INIT_EVERYTHING); screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); SDL_Surface *alienImage = IMG_Load("space_invader.bmp"); SDL_SetColorKey(alienImage, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(alienImage->format, 255, 255, 255)); SDL_Rect alienPos; alienPos.x = 0; alienPos.y = 10; alienPos.h = alienImage->h; alienPos.w = alienImage->w; while(1){ SDL_BlitSurface(alienImage,NULL,screen,&alienPos); SDL_Flip(screen); if( SDL_PollEvent( &event ) ){ switch(event.type){ case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_ESCAPE: SDL_Quit(); exit(0); break; default: break; } break; default: break; } } } SDL_FreeSurface(alienImage); SDL_Quit(); } |
O comando SDL_BlitSurface() desenha a imagem no buffer (invisível, somente na memória) de nossa tela (visível) e o comando SDL_Flip() troca o buffer com a imagem visível. Isso é feito porque desenhar na memória é muito mais rápido que desenhar na tela diretamente.
Com isso, nossa imagem terá a cor branca como transparente na hora de pintar e apenas parada na tela.
Vamos adicionar um pouco de movimento fazendo a imagem ir de um lado a outro da tela:
#include "SDL/SDL.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Surface *screen; SDL_Event event; SDL_Init(SDL_INIT_EVERYTHING); screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); SDL_Surface *alienImage = IMG_Load("space_invader.bmp"); SDL_SetColorKey(alienImage, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(alienImage->format, 255, 255, 255)); SDL_Rect alienPos; alienPos.x = 0; alienPos.y = 10; alienPos.h = alienImage->h; alienPos.w = alienImage->w; while(1){ SDL_BlitSurface(alienImage,NULL,screen,&alienPos); SDL_Flip(screen); if(alienPos.x>640){ alienPos.x = 0; }else{ alienPos.x = alienPos.x + 5; } if( SDL_PollEvent( &event ) ){ switch(event.type){ case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_ESCAPE: SDL_Quit(); exit(0); break; default: break; } break; default: break; } } } SDL_FreeSurface(alienImage); SDL_Quit(); } |
As coisas se mexeram, porém, a imagem “borrou” a tela toda. Vamos então, antes de mover o alien, desenhar um retângulo preto cobrindo toda a tela. Por último inserimos uma espera para o movimento ficar mais suave:
#include "SDL/SDL.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Surface *screen; SDL_Event event; SDL_Init(SDL_INIT_EVERYTHING); screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); SDL_Surface *alienImage = IMG_Load("space_invader.bmp"); SDL_SetColorKey(alienImage, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(alienImage->format, 255, 255, 255)); SDL_Rect alienPos; alienPos.x = 0; alienPos.y = 10; alienPos.h = alienImage->h; alienPos.w = alienImage->w; while(1){ SDL_FillRect(screen, NULL, 0); SDL_BlitSurface(alienImage,NULL,screen,&alienPos); SDL_Flip(screen); if(alienPos.x>640){ alienPos.x = -(alienImage->w); }else{ alienPos.x = alienPos.x + 5; } if( SDL_PollEvent( &event ) ){ switch(event.type){ case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_ESCAPE: SDL_Quit(); exit(0); break; default: break; } break; default: break; } } SDL_Delay(50); } SDL_FreeSurface(alienImage); SDL_Quit(); } |
Podemos usar algumas funções matemáticas para construir as trajetórias que nosso personagem vai seguir:
#include "SDL/SDL.h" #include "math.h" #include "SDL/SDL_image.h" int main( int argc, char* argv[]) { SDL_Surface *screen; SDL_Event event; SDL_Init(SDL_INIT_EVERYTHING); screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF | SDL_HWSURFACE); SDL_Surface *alienImage = IMG_Load("space_invader.bmp"); SDL_SetColorKey(alienImage, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(alienImage->format, 255, 255, 255)); SDL_Rect alienPos; alienPos.x = 0; alienPos.y = 10; alienPos.h = alienImage->h; alienPos.w = alienImage->w; float c = 0.0; while(1){ SDL_FillRect(screen, NULL, 0); SDL_BlitSurface(alienImage,NULL,screen,&alienPos); SDL_Flip(screen); if(c>2*M_PI){ c = 0.0; }else{ c = c + 0.05; alienPos.x = (600/2)*(1+cos(c)); } if(alienPos.y>480){ alienPos.y = -(alienImage->h); }else{ alienPos.y = alienPos.y + 10; } if( SDL_PollEvent( &event ) ){ switch(event.type){ case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_ESCAPE: SDL_Quit(); exit(0); break; default: break; } break; default: break; } } SDL_Delay(50); } SDL_FreeSurface(alienImage); SDL_Quit(); } |
Com isto é possível criar algumas animações bem básicas e ter uma idéia do funcionamento do SDL. Entretanto, existem muito mais recursos e técnicas disponíveis para aumentar o desempenho (e segurança) da aplicação e só um estudo mais aprofundado do SDL pode mostrar tais.
Veja também: http://igorknop.com.br/wp/hobby/sdl-intro-2.
Deixe uma resposta