Pular para o conteúdo

Tutorial SDL

Tutorial sobre a biblioteca SDL com exemplos práticos.
Samuel Leonardo SamL
Hits: 50.440 Categoria: C/C++ Subcategoria: Metodologias
  • Indicar
  • Impressora
  • Denunciar
O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

Parte 4: 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;
}
O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.

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.

O Viva o Linux depende da receita de anúncios para se manter. Ative os cookies aqui para nos patrocinar.
Não conseguimos carregar os anúncios. Se usa bloqueador, considere liberar o Viva o Linux para nos patrocinar.
   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

Desenhando fácil um pinguim no Inkscape

A arte e a prática da Disciplina a longo prazo

Desenhando um avatar do Tux no InkScape

Dicas para aprender programação

Extrair arquivos executáveis feito em código Python e executá-los no seu GNU/Linux

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

Algoritmo... como fazer?

Otimização de algoritmos

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

Linguagem C - Árvores Binárias

#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

Entre na sua conta para comentar.