Tutorial SDL

Tutorial sobre a biblioteca SDL com exemplos práticos.

[ Hits: 47.764 ]

Por: Samuel Leonardo em 01/11/2013


Eventos no SDL



Para ler eventos, usaremos uma função chamada SDL_PollEvent, que lerá a fila de eventos e colocará o mais antigo numa variável SDL_Event.

Internamente, o SDL enfileira os eventos e a cada chamada de SDL_PollEvent, será posto numa variável SDL_Event, o evento mais antigo e assim poderá ser processado da maneira que quisermos.

O próximo programa mostrará como fechar a janela principal, esse programa servirá de base para os próximos.

Fechando uma janela

Arquivo: eventos_01.c

#include <SDL/SDL.h>

int main()
{
  SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
  SDL_Surface * screen; // A janela principal
  SDL_Event event; // Para os eventos

  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela

  int done = 0; // Variável de controle do loop
  while (done == 0) // Loop principal
  {
     // Lê a fila de eventos e põe o evento mais antigo em "event"
     while (SDL_PollEvent(&event)) // Loop de eventos
     {
        // Verifica se o evento mais antigo é do tipo SDL_QUIT
        if (event.type == SDL_QUIT) // Se o usuário clicou para fechar a janela
          done = 1; // Encerre o loop
     }
  }

  SDL_Quit(); // Fecha o SDL
  return 0;
}

Para compilar:

gcc -o eventos_01 eventos_01.c -lSDL

SDL_Event event; :: variável para tratar os eventos. SDL_Event é a estrutura de todos os eventos do SDL. Tem dois usos específicos: ler eventos da fila de eventos e colocar evento na fila de eventos. Por enquanto, apenas ler os evento é o bastante. Há duas funções que leem eventos, que são: SDL_PollEvent e SDL_PeepEvetns. Mas vamos usar somente SDL_PollEvent.

while (SDL_PollEvent(&event)) :: aqui estamos lendo toda a fila de eventos. Esse é o motivo de usar um while, se usássemos um if, apenas um evento seria lido (o mais antigo, é claro). Enquanto houver eventos na fila SDL_PollEvent, retornará 1, se não houver retorna 0. Ele recebe um ponteiro para um SDL_Event que será preenchido com o evento mais antigo da fila de eventos.

if (event.type == SDL_QUIT) :: verifica se o evento atual lido da fila de eventos é do tipo SDL_QUIT. Esse evento é chamado assim que o usuário clica sobre o botão fechar da janela.

Manipulação do mouse

1. Movimento do mouse:

Arquivo: eventos_02.c

#include <SDL/SDL.h>
#include <stdio.h>


int main()
{
  SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
  SDL_Surface * screen; // A janela principal
  SDL_Event event; // Para os eventos

  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela

  int done = 0; // Variável de controle do loop
  while (done == 0) // Loop principal
  {
     // Lê a fila de eventos e põe o evento mais antigo em "event"
     while (SDL_PollEvent(&event)) // Loop de eventos
     {
        // Verifica se o evento mais antigo é do tipo SDL_QUIT
        if (event.type == SDL_QUIT) // Se o usuário clicou para fechar a janela
          done = 1; // Encerre o loop

        // Verifica se o evento mais antigo é do tipo SDL_MOUSEMOTION

        if (event.type == SDL_MOUSEMOTION) // Se o usuário moveu o cursor sobre a tela
        {
          printf("Moveu o cursor para X = %d, Y = %d\n", event.motion.x, event.motion.y);
        }
     }
  }

  SDL_Quit(); // Fecha o SDL
  return 0;
}

Para compilar:

gcc -o eventos_02 eventos_02.c -lSDL

if (event.type == SDL_MOUSEMOTION) :: verifica se o tipo de evento é SDL_MOUSEMOTION (movimento do mouse). Esse tipo de evento só é identificado se o cursor estiver sobre a janela principal. Fora dela, mesmo com movimento do mouse, nenhum evento é disparado.

Poderia alterar o programa para colocar uma imagem sob o ponteiro do mouse. Bastava apenas criar uma variável SDL_Rect com nome dest e setar as coordenadas para a posição do cursor. Veja abaixo:

Arquivo: eventos_03.c

#include <SDL/SDL.h>
#include <stdio.h>


int main()
{
  SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
  SDL_Surface * screen; // A janela principal
  SDL_Surface * image; // A imagem
  SDL_Event event; // Para os eventos
  SDL_Rect dest; // Destino da imagem dentro do screen

  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela
  image = SDL_LoadBMP("ball.bmp"); // Carrega o arquivo de imagem

  // Verifica se carregou a imagem

  if (image == NULL)
  {
     printf("Não foi possivel abrir ball.bmp\n");
     return 1;
  }

  int done = 0; // Variável de controle do loop
  while (done == 0) // Loop principal
  {
     while (SDL_PollEvent(&event)) // Lê a fila de eventos e põe o evento mais antigo em "event"
     {
        // Verifica se o evento mais antigo é do tipo SDL_QUIT
        if (event.type == SDL_QUIT) // Se o usuário clicou para fechar a janela
          done = 1; // Encerre o loop

        // Verifica se o evento mais antigo é do tipo SDL_MOUSEMOTION
        if (event.type == SDL_MOUSEMOTION) // Se o usuário moveu o cursor sobre a tela
        {
          printf("Moveu o cursor para X = %d, Y = %d\n", event.motion.x, event.motion.y);
          // Seta o destino da imagem para as coordenadas do cursor
          dest.x = event.motion.x; // Posição do cursor no eixo X
          dest.y = event.motion.y; // Posição do cursor no eixo Y
        }
     }

    SDL_FillRect(screen, NULL, 0x0); // Pinta de preto todo o screen
    SDL_BlitSurface(image, NULL, screen, &dest); // Joga a imagem no "screen" em "dest"
    SDL_UpdateRect(screen, 0,0,0,0); // Atualiza todo o screen
    SDL_Delay(60); // Espera 60 milissegundos
  }

  SDL_Quit(); // Fecha o SDL
  return 0;
}

Para compilar:

gcc -o eventos_03 eventos_03.c -lSDL

Se você apagar a linha com SDL_FillRect(screen, NULL, 0x0); poderá ver o por quê de ter que pintar todo o screen com uma cor antes de "blitar" uma imagem. A tela ficará toda "suja" com blitagem passadas de "image". Fica parecendo até bug do Windows. (rsrs)

2. Botão do mouse:

Arquivo: eventos_04.c

#include <SDL/SDL.h>
#include <stdio.h>


int main()
{
  SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
  SDL_Surface * screen; // A janela principal
  SDL_Event event; // Para os eventos

  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela

  int done = 0; // Variável de controle do loop
  while (done == 0) // Loop principal
  {
     while (SDL_PollEvent(&event)) // Lê a fila de eventos e põe o evento mais antigo em "event"
     {
        // Verifica se o evento mais antigo é do tipo SDL_QUIT
        if (event.type == SDL_QUIT) // Se o usuário clicou para fechar a janela
          done = 1; // Encerre o loop

        // Verifica se o evento mais antigo é do tipo SDL_MOUSEBUTTONDOWN

        if (event.type == SDL_MOUSEBUTTONDOWN) // Se o usuário clicou
        {
          if (event.button.button == SDL_BUTTON_LEFT)
            printf("APERTOU o botão do mouse: botão ESQUERDO\n");
          else if (event.button.button == SDL_BUTTON_RIGHT)
            printf("APERTOU o botão do mouse: botão DIREITO\n");
        }

        // Verifica se o evento mais antigo é do tipo SDL_MOUSEBUTTONUP
        if (event.type == SDL_MOUSEBUTTONUP) // Se o usuário clicou
        {
          if (event.button.button == SDL_BUTTON_LEFT)
            printf("SOLTOU o botão do mouse: botão ESQUERDO\n");
          else if (event.button.button == SDL_BUTTON_RIGHT)
            printf("SOLTOU o botão do mouse: botão DIREITO\n");
        }
     }
  }

  SDL_Quit(); // Fecha o SDL
  return 0;
}

Para compilar:

gcc -o eventos_04 eventos_04.c -lSDL

if (event.type == SDL_MOUSEBUTTONDOWN) :: verifica se apertou um botão do mouse.

if (event.type == SDL_MOUSEBUTTONUP) :: verifica se soltou um botão do mouse. Em event o botão pressionado ou solto fica armazenado em button que é do tipo SDL_MouseButtonEvent. Essa estrutura contém outros membros como posição do clique (x e y) e estado do botão (state).

Exercício: colocar uma imagem na posição onde o usuário clicar. Use man SDL_MouseButtonEvent, para mais informação.

Manipulando o teclado

1. Evento de pressionar e soltar de tecla:

Arquivo: eventos_05.c

#include <SDL/SDL.h>
#include <stdio.h>


int main()
{
  SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
  SDL_Surface * screen; // A janela principal
  SDL_Event event; // Para os eventos

  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela

  int done = 0; // Variável de controle do loop
  while (done == 0) // Loop principal
  {
     while (SDL_PollEvent(&event)) // Lê a fila de eventos e põe o evento mais antigo em "event"
     {
        // Verifica se o evento mais antigo é do tipo SDL_QUIT
        if (event.type == SDL_QUIT) // Se o usuário clicou para fechar a janela
          done = 1; // Encerre o loop

        // Verifica se o evento mais antigo é do tipo SDL_KEYDOWN

        if (event.type == SDL_KEYDOWN) // Se o usuário apertou um botão do teclado
        {
          printf("APERTOU uma tecla\n");
        }
        // Verifica se o evento mais antigo é do tipo SDL_KEYUP
        if (event.type == SDL_KEYUP) // Se o usuário soltou um botão do teclado
        {
          printf("SOLTOU uma tecla\n");
        }
     }
  }

  SDL_Quit(); // Fecha o SDL
  return 0;
}

Para compilar:

gcc -o eventos_05 eventos_05.c -lSDL

if (event.type == SDL_KEYDOWN) :: verifica se o usuário apertou uma tecla do teclado.

if (event.type == SDL_KEYUP) :: verifica se o usuário soltou uma tecla do teclado. O teclado só produz esses dois tipos de eventos.

2. Identificando teclas pressionada ou solta:

Arquivo: eventos_06.c

#include <SDL/SDL.h>
#include <stdio.h>


int main()
{
  SDL_Init(SDL_INIT_VIDEO); // Inicializa o SDL e o sistema de vídeo
  SDL_Surface * screen; // A janela principal
  SDL_Event event; // Para os eventos

  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE); // Cria a janela

  int done = 0; // Variável de controle do loop
  while (done == 0) // Loop principal
  {
     // Lê a fila de eventos e põe o evento mais antigo em "event"
     while (SDL_PollEvent(&event)) // Loop de eventos
     {
        // Verifica se o evento mais antigo é do tipo SDL_QUIT
        if (event.type == SDL_QUIT) // Se o usuário clicou para fechar a janela
          done = 1; // Encerre o loop

        // Verifica se o evento mais antigo é do tipo SDL_KEYDOWN

        if (event.type == SDL_KEYDOWN) // Se o usuário apertou um botão do teclado
        {
          printf("APERTOU uma tecla: ");
          // Verifica qual tecla foi apertada
          switch (event.key.keysym.sym)
          {
            case SDLK_UP:
              printf("Seta para CIMA\n");
              break;
            case SDLK_DOWN:
              printf("Seta para BAIXO\n"):
              break;
            case SDLK_RIGHT:
              printf("Seta DIREITA\n");
              break;
            case SDLK_LEFT:
              printf("Seta ESQUERDA\n");
              break;
           default:
              break;
          }
        }
        if (event.type == SDL_KEYUP) // Se o usuário soltou um botão do teclado
        {
          printf("SOLTOU uma tecla: ");
          // Verifica qual tecla foi solta
          switch (event.key.keysym.sym)
          {
            case SDLK_UP:
              printf("Seta para CIMA\n");
              break;
            case SDLK_DOWN:
              printf("Seta para BAIXO\n"):
              break;
            case SDLK_RIGHT:
              printf("Seta DIREITA\n");
              break;
            case SDLK_LEFT:
              printf("Seta ESQUERDA\n");
              break;
           default:
              break;
          }
        }
     }
  }

  SDL_Quit(); // Fecha o SDL
  return 0;
}

Para compilar:

gcc -o eventos_06 eventos_06.c -lSDL

switch (event.key.keysym.sym)      case SDLK_UP:
       printf("Seta para CIMA\n");
       break;

Aqui estamos verificando qual tecla foi apertada/solta. Dessa vez, a estrutura das tecla é um pouco mais longa, event.key.keysym.sym é preciso acessar duas estruturas para saber o código/símbolo da tecla apertada/solta.

Todo símbolo de tecla no SDL começa com SDLK_ seguida da tecla. Então, se, por exemplo, quisermos a tecla a use SDLK_a, tecla b use SDLK_b e assim por diante.

Mas, há teclas que não seguem esse padrão, as teclas do teclado numérico, por exemplo, use SDLK_KP_"número da tecla". Para saber sobre todos os símbolos, use man SDLKey no terminal.

Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. Aplicação básica
   3. Dando vida ao programa: o loop principal
   4. Eventos no SDL
   5. Controlando uma imagem com o teclado
Outros artigos deste autor

Criatividade para TI parte 1

Dicas para aprender programação

Algoritmo Antissocial - Recuperando o Controle da sua Mente

Desenhando fácil um pinguim no Inkscape

Desenhando um avatar do Tux no InkScape

Leitura recomendada

Otimização de algoritmos

Linguagem C - Árvores Binárias

Análise dos Métodos de Ordenação usados em Algoritmos Computacionais

Linguagem C - Listas Duplamente Encadeadas

Guia de Programação em C/GTK 2 - Construindo uma Calculadora Completa

  
Comentários
[1] Comentário enviado por nelson777 em 01/11/2013 - 15:40h

Finalmente um artigo de C que não é só mais um algoritmo básico de criança e sim algo útil. Parabéns.

[2] Comentário enviado por tsuriu em 03/11/2013 - 20:49h

Parabéns cara... Muito bom o artigo.

[3] Comentário enviado por danilo3610 em 04/11/2013 - 08:53h

Muito bom tutorial Samuel, segui passo a passo este tutorial no meu ubuntu 13.10 64bits,
instalei o SDL_DEV e usei o seu primeiro exemplo porem ao compilar (incluindo -ISDL)
apresentava erros com SDL_Init - "Undefined reference to SDL_Init...". Procurei na net
mas ninguem teve este mesmo problema, já aconteceu com alguem? Se alguem tiver alguma
solução agradeço. Lembrando instalei o SDL_DEV como mostra o tutorial.

att.

[4] Comentário enviado por SamL em 04/11/2013 - 11:32h

Esse problema geralmente acontece quando NÃO se usa -lSDL no final do comando. Veja se você compilou assim: gcc -o janela_01 janela_01.c -lSDL
com o link -lSDL no final.
Se não resolver talvez você tenha instalado a SDL 2.0, veja na pasta /usr/include/ se tem a pasta SDL2.
Se também não resolver, não sei mais o que fazer rsrsrs

[5] Comentário enviado por danilo3610 em 04/11/2013 - 14:00h

Talvez tenha confundido mas só uma duvida, a primeira letra é um l ou i maiúsculo? Desconfio que seja um L minúsculo e
tenha colocado um i maiúsculo no lugar. Quando chegar em casa irei testar.

[6] Comentário enviado por SamL em 04/11/2013 - 14:03h

É um L minúsculo. Avisa se funcionar quando testar.

[7] Comentário enviado por danilo3610 em 04/11/2013 - 19:24h

Era isso mesmo, troquei o I pelo l e funcionou, obrigado.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts