SDL e programação de jogos parte 2

Caso vc não tenha visto, aqui o link pra parte 1:
Neste post, veremos como mover pela tela um retângulo simples, além de desenhar na janela com o renderer.

Para fazer isso, vamos primeiro ver como criar o loop principal e aprender sobre funções de desenhar na tela, veja abaixo: O código acima não faz nada de muito útil, mas podemos melhorar, veja:
#include <SDL2/SDL.h>
#include <stdio.h>
int main() {
  SDL_Init(SDL_INIT_VIDEO);
  //100 posição horizontal em pixels dentro do seu monitor do canto esquerdo superior para direita
  //150 posição vertical em pixels dentro do seu monitot do canto esquerdo superior pra baixo
  //640 é a largura da janela em pixel
  //480 é a altura da janela em pixel
  SDL_Window * janela = SDL_CreateWindow("loops e jogos", 100,150,640,480, SDL_WINDOW_OPENGL);
  SDL_Renderer * renderer = SDL_CreateRenderer(janela, -1, SDL_RENDERER_ACCELERATED);
  
  SDL_Event evento;
  
  int fim = 0;
  //loop principal
  while (!fim) {
    //loop de eventos
    while (SDL_PollEvent(&evento)) {
      //verifica se clicou em fechar
      if (evento.type == SDL_QUIT)
        fim = 1;
    }
    
    //código de update
    //faz mover, faz pular, etc
    
    //código de desenho na tela
    //aqui é onde o usuário vê o resultado na tela
    
    //tem que chamar essa função pra mostrar tudo na janela
    SDL_RenderPresent(renderer);
    //NOTA: tem que esperar um pouco antes de ir pra próxima iteração
    SDL_Delay(16);
  }
  //por fim libera memória
  SDL_DestroyRenderer(renderer);
  SDL_DestroyWindow(janela);
  SDL_Quit();
  return 0;
}
Salve o código acima como sdl_loops.c compile com:
gcc -o sdl_loops sdl_loops.c -lSDL2

Veja que criamos dois loops, um while(!fim){...} que é nosso loop principal e dentro dele um while(SDL_PollEvent(&event)){...} que é nosso loop de eventos.

Todo jogo é feito principalmente de um loop principal e dentro dele o loop de eventos, em geral, o loop de eventos vem bem no comecinho do loop principal.

Abaixo do loop de eventos, viria o código de atualização do game e depois dele, viria o código de desenho na tela que é onde coloca tudo pra ser visualizado pelo usuário

Veja abaixo a imagem esquemática do loop principal com todas suas partes:

Desenhando um retângulo na tela

Para desenhar um retângulo na tela, vc precisa usara função SDL_RenderFillRect(), com ela vc coloca o renderer como parâmetro e um ponteiro para um SDL_Rect, SDL_Rect nada mais é que uma struct com esses dados:

typedef struct SDL_Rect {
  int x;//posição horizontal do rect localizada no canto superior esquerdo do rect
  int y;//posição vertical do rect localizada no canto superior esquerdo do rect
  int w;//largura do rect
  int h;//altura do rect
} SDL_Rect;
Para desenhar na tela, vc deve chamar a função SDL_RenderFillRect dentro do loop principal, então, ela vai ser chamada todo tempo para refazer o desenho na tela.

Lembre-se que a orientação do SDL é do canto esquerdo superior pra direita para eixo x, e do canto esquerdo superior para baixo para o eixo y! Ou seja, pra direita é o posiivo do eixo X e pra baixo é o positivo do eixo Y

Antes de desenhar tela, vc precisa desenhar uma cor por cima de toda a tela, isso se chama limpar a tela, veja como é feito:


  //...dentro do loop principal
  //código de desenho na tela
  //primeiro, limpa a tela
  //aqui é onde o usuário vê o resultado na tela
  //define uma cor para desenhar, no caso 0,0,0,255 é a cor preta
  SDL_SetDrawColor(renderer, 0,0,0,255);
  //agora desenha a cor acima em toda a tela
  SDL_RenderClear(renderer);
  //...até aqui tudo estará preto!
Cópie o código acima e cole na parte onde tem //código de desenho na tela.
Compile com o mesmo comando de antes!

Exercício veja o que acontece:

1--onde tem os número 0,0,0 coloque outros 3 números entre 0 e 255, salve, recompile e execute. Veja o que acontece
2--onde tinha os 3 números 0, faça assim: o primeiro 0 coloque 255, o segundo e o terceiro mantenha o 0. Salve,recompile e execute pra ver o que acontece.
3--depois de fazer o exercício 2, experimente fazer o mesmo com os outros 2 parâmetros. Ou seja, experimente 0,255,0 e depois 0,0,255, salve, compile e execute, veja o que acontece em cada caso.
4--experimente misturar as cores colocando valores aleatórios nesses 3 parâmetros. Experimente e veja como fica.

Se vc executou cada exercício acima, vc verá algo interessante: quando vc coloca 255,0,0 nos três parâmetros, tudo fica vermelho e quando vc colocou 0,255,0 nos três parâmetros tudo ficou verde e quando vc colocou 0,0,255 nos três parâmetros tudo ficou azul.
Deu pra reconhecer o padrão?
No caso, cada vez que o parâmetro não era 0, tudo ficava numa certa cor, isso significa que cada parâmtero controla um canal de cor. Ou seja:

SDL_SetRenderDrawColor(renderer, Red, Green, Blue, 255); //primeiro, define a cor
SDL_RenderClear(renderer);//depois, desenha em toda a tela a cor definida acima

Definindo um retângulo como player

Antes e fora do loop principal, crie uma variável de retângulo assim: SDL_Rect player, ou cópie e cole o código abixo:
//...copie e cole o código abaixo antes do while(!fim)
  SDL_Rect player;
  player.x = 320;//posição horizontal inicial do player
  player.y = 240;//posição vertical inicial do player
  player.w = 32;//lagura do player
  player.h = 64;//altura do player
  
E ai dentro do loop principal, depois de executar SDL_RenderClear, coloque o código abaixo:

//...cole depois de SDL_RenderClear
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); //define a cor do player para amarelo
SDL_RenderFillRect(renderer, &player);//depois, desenha o retangulo amarelo usando o retângulo do player
//...antes do SDL_RenderPresent(renderer);
Observe que, pra fazer este retângulo mover na tela, basta apenas modificar o layer.x ou o player.y. Veja os exercícios:

1--experimente fazer o seguinte: dentro do loop principal abaixo do comentário com //código de update coloque este código: player.x += 1; Salve, compile e execute para ver que acontece
2--depois, troque o player.x += 1; por player.y += 1; e salve, compile e execute para vr o que acontece.
3--depois, coloque as duas linhas player.x += 1; e depois abaixo dele coloque player.y += 1; e mais uma vez, salve, compile e execute pra ver o que acontece.
4--experimente subtrair ao invés de somar pra ver o que acontece.
5--ao invés de somar +1 experimente colocar +5 ou +10 ou +300 e veja o que acontece.

O que vc vai observar é que assim que o programa foi executado, o player começou mover numa direção horizontal para a direita para o exercício 1, depois para baixo no exercício 2 e depois para a diagonal pra baixo no exercício 3. Ou seja, vc pode fazer o retângulo mover apenas modificando os membros x/y dele.

No exercício 5 vc mudou os valores e quando maior os valores, mais rápido o retângulo movia na tela.

Movendo o player com as setas do teclado

Bem, agora chegou o momento de mover com o teclado! Yeeeeaaah!

Pra mover com o teclado, primeiro, vc precisa detectar quando as setas estão pressionadas e ai mover o player.x ou player.y.

Por exemplo, suponha que vc aperte seta pra baixo, como mover o player? Ora, se é pra mover pra baixo vc deve somar player.y com +5 pra mover +5 pixels pra baixo. Lembre-se que o eixo Y está apontando pra baixo!

Chega de conversa veja um exemplo prático:


//loop de eventos
//novo loop de eventos
while (SDL_PollEvent(&evento)) {
  //verifica se clicou em fechar
  if (evento.type == SDL_QUIT)
    fim = 1;
  //verifica se a tecla pra baixo foi apertada
  if (evento.type == SDL_KEYDOWN) {
    if (evento.key.keysym.sym == SDLK_DOWN) {
      //move o player pra baixo +5 pixels
      player.y = player.y + 5;
    }
    //verifica se a tecla apertada é a seta direita
    else if (evento.key.keysym.sym == SDLK_RIGHT) {
      //move o player +5 pixels pra direta
      player.x = player.x + 5;
    }
    //se é a tecla seta esquerda
    else if (evento.key.keysym.sym == SDLK_LEFT) {
      //mova pra esquerda, como que faz?
      //se somar +5 ao player.x é mover pra direita, então diminiuir -5 em player.x é mover pra esquerda!
    }
    else if (evento.key.keysym.sym == SDLK_UP) {
      //mmova pra cima, como que faz?
      //se mover pra baixo é somar +5 ao player.y, então, mover pra cima é diminuir -5 no player.y!
    }
  }
}
No código do loop de eventos, cópie o código acima e cole em todo o loop de eventos!

Este código serve para ler as setas do teclado e vc deve fazer os outros "if".

A partir desse ponto, vc já deve ser capaz de controlar um retângulo pela janela!

Baixe o código completo aqui do meu gist do github:
SDL_loops.c

No próximo tutorial, veremos como detectar colisão entre dois retângulos e então separar um de dentro do outro.

Até mais!

Comentários

Postagens mais visitadas deste blog

SDL e programação de jogos parte 1

SDL e programação de jogos - detecção de colisão - parte 3