Programação de Jogos com SDL
Este é um tutorial 2 em 1, vamos programar passo a passo dois jogos. O primeiro jogo será um jogo de labirinto e o segundo um snake (jogo da cobrinha). Os jogos serão feitos usando linguagem C e a biblioteca SDL.
[ Hits: 26.612 ]
Por: Samuel Leonardo em 18/11/2013 | Blog: https://nerdki.blogspot.com.br/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <SDL/SDL.h>
/* direções da cobra */
#define CIMA 0
#define DIREITA 1
#define BAIXO 2
#define ESQUERDA 3
#define TAMANHOIMAGEM 32
struct Pedaco
{
int coorX;
int coorY;
int direcao; // direção
} pedaco[256], maca; // pedaco[0] = ponta do rabo E pedaco[tamanho - 1] = cabeça
/* Imagens e tela principal */
SDL_Surface *tela, *img_maca, *img_snakes, *img_cabeca;
int seta_cima = 0, seta_baixo = 0, seta_esquerda = 0, seta_direita = 0;
int colisao = 0; // identifica colisao da cabeça com outras partes do corpo
// tamanho = tamanho atual da cobra
int tamanho = 5, tamanho_anterior = 5;
int velX = 0, velY = 0; // para mover a cobra
int mapa_largura = 25, mapa_altura = 20; // dimensões do mapa
char hud[256]; // informações passadas ao usuario
/* Funcao que controla o fps */
void controla_fps ( int tempo_inicial )
{
int fps = 1000/7; // converte 7 FPS para milissegundos
int tempo_agora = SDL_GetTicks() - tempo_inicial;
if(tempo_agora < fps)
SDL_Delay(fps - tempo_agora);
}
int carrega_imagens ( )
{
img_maca = SDL_LoadBMP("apple.bmp");
if (img_maca == NULL)
{
printf("Não carregou apple.bmp\n");
return 0;
}
img_snakes = SDL_LoadBMP("piece.bmp");
if (img_snakes == NULL)
{
printf("Não carregou piece.bmp\n");
return 0;
}
img_cabeca = SDL_LoadBMP("head.bmp");
if (img_cabeca == NULL)
{
printf("Não carregou head.bmp\n");
return 0;
}
return 1;
}
void posiciona_maca ( )
{
int i;
int repetir;
do
{
// escolhe aleatoriamente as coordenadas
maca.coorX = rand() % mapa_largura;
maca.coorY = rand() % mapa_altura;
repetir = 0;
for (i = 0; i < tamanho; i++)
{
// verifica em todas as peças se as coordenadas delas
// são iguais as novas coordenadas da maçã.
if ((pedaco[i].coorX == maca.coorX) && (pedaco[i].coorY == maca.coorY))
{
// Se forem iguais então pare o loop e
// repita o procedimento para escolher outra coordenada para a maçã.
repetir = 1;
break;
}
}
// enquanto for para repetir continue escolhendo outra coordenada para a maçã.
} while (repetir);
}
void inicia_jogo ( )
{
tamanho_anterior = tamanho; // para o hud
//Reinicie o jogo
tamanho = 5;
colisao = 0;
velX = 0;
velY = 0;
// reinicializando as peças
// inicializando a parte A - a cabeça
pedaco[4].coorX = 5;
pedaco[4].coorY = 3;
pedaco[4].direcao = DIREITA;
// inicializando a parte B
pedaco[3].coorX = 4;
pedaco[3].coorY = 3;
pedaco[3].direcao = DIREITA;
// inicializando a parte C
pedaco[2].coorX = 3;
pedaco[2].coorY = 3;
pedaco[2].direcao = DIREITA;
// inicializando a parte D
pedaco[1].coorX = 2;
pedaco[1].coorY = 3;
pedaco[1].direcao = DIREITA;
// inicializando a parte E - o rabo
pedaco[0].coorX = 1;
pedaco[0].coorY = 3;
pedaco[0].direcao = DIREITA;
// inicializando as coordenadas da maçã.
posiciona_maca();
}
void controla_snake ( SDL_Event evento )
{
if (evento.type == SDL_KEYDOWN)
{
switch (evento.key.keysym.sym)
{
case SDLK_RIGHT:
seta_direita = 1;
break;
case SDLK_LEFT:
seta_esquerda = 1;
break;
case SDLK_UP:
seta_cima = 1;
break;
case SDLK_DOWN:
seta_baixo = 1;
break;
case SDLK_p:
velX = 0;
velY = 0;
break;
default:
break;
}
}
else if (evento.type == SDL_KEYUP)
{
switch (evento.key.keysym.sym)
{
case SDLK_RIGHT:
seta_direita = 0;
break;
case SDLK_LEFT:
seta_esquerda = 0;
break;
case SDLK_UP:
seta_cima = 0;
break;
case SDLK_DOWN:
seta_baixo = 0;
break;
default:
break;
}
}
}
void move_snake ( )
{
if (seta_direita && pedaco[tamanho - 1].direcao != ESQUERDA)
{
velX = 1; // move horizontalmente a cabeça para direita
velY = 0; // e para de mover verticalmente
pedaco[tamanho - 1].direcao = DIREITA;
}
else if (seta_esquerda && pedaco[tamanho - 1].direcao != DIREITA)
{
velX = -1; // move horizontalmente a cabeça para esquerda
velY = 0; // e para de mover verticalmente
pedaco[tamanho - 1].direcao = ESQUERDA;
}
else if (seta_cima && pedaco[tamanho - 1].direcao != BAIXO)
{
velX = 0; // para de mover horizontalmente
velY = -1; // e move verticalmente a cabeça
pedaco[tamanho - 1].direcao = CIMA;
}
else if (seta_baixo && pedaco[tamanho - 1].direcao != CIMA)
{
velX = 0; // para de mover horizontalmente
velY = 1; // e move verticalmente a cabeça
pedaco[tamanho - 1].direcao = BAIXO;
}
// depois ajustando as posições das outras peças (partes)
// primeiro move as partes do corpo
if (velX || velY) // se estiver movendo
{
int i;
for (i = 0; i < tamanho - 1; i++)
{
// faça a peça de trás (pedaco[i]) igual a peça da frente (pedaco[i + 1])
pedaco[i].coorX = pedaco[i + 1].coorX;
pedaco[i].coorY = pedaco[i + 1].coorY;
pedaco[i].direcao = pedaco[i + 1].direcao;
}
}
// agora move a cabeça
pedaco[tamanho - 1].coorX += velX;
pedaco[tamanho - 1].coorY += velY;
// Verifica os limites do movimento da cobra
// Para o eixo X
// se estiver além da largura da tela/mapa
if (pedaco[tamanho - 1].coorX >= mapa_largura)
{
// volte para posição coorX = 0
pedaco[tamanho - 1].coorX = 0;
}
else if (pedaco[tamanho - 1].coorX < 0) // se estiver além de 0
{
// volte para a posição da largura do mapa
pedaco[tamanho - 1].coorX = mapa_largura - 1;
}
// Para o eixo Y
if (pedaco[tamanho - 1].coorY >= mapa_altura)
{
pedaco[tamanho - 1].coorY = 0;
}
else if (pedaco[tamanho - 1].coorY < 0)
{
pedaco[tamanho - 1].coorY = mapa_altura - 1;
}
}
void desenha_snake ( )
{
int i;
SDL_Rect destino;
// blitando as img_macas das peças
for (i = 0; i < tamanho - 1; i++)
{
destino.y = pedaco[i].coorY * TAMANHOIMAGEM;
destino.x = pedaco[i].coorX * TAMANHOIMAGEM;
SDL_BlitSurface(img_snakes, NULL, tela, &destino);
}
// blitando a cabeça
destino.y = pedaco[tamanho - 1].coorY * TAMANHOIMAGEM;
destino.x = pedaco[tamanho - 1].coorX * TAMANHOIMAGEM;
SDL_BlitSurface(img_cabeca, NULL, tela, &destino);
}
int main (int argc, char **args)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("ERROR: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_Event evento;
// controle do FPS
Uint32 tempo_inicial;
tela = SDL_SetVideoMode(mapa_largura * TAMANHOIMAGEM, mapa_altura * TAMANHOIMAGEM, 16, SDL_SWSURFACE);
if (tela == NULL)
{
printf("ERROR: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
if (carrega_imagens() == 0)
{
printf("ERROR: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
// inicia o jogo
inicia_jogo();
srand(time(NULL));
int i;
int fim = 0; // variável de controle do loop principal
while (!fim)
{
tempo_inicial = SDL_GetTicks();
sprintf(hud, "SNAKE by Sam L. - TAMANHO: ATUAL = %d | ANTERIOR = %d", tamanho, tamanho_anterior);
SDL_WM_SetCaption(hud, NULL);
while (SDL_PollEvent(&evento))
{
if (evento.type == SDL_QUIT)
{
fim = 1;
break;
}
controla_snake(evento);
}
// move a cobra
move_snake();
// colisão com a maçã
if ((pedaco[tamanho - 1].coorX == maca.coorX) &&
(pedaco[tamanho - 1].coorY == maca.coorY))
{
tamanho++;
pedaco[tamanho - 1].coorX = maca.coorX;
pedaco[tamanho - 1].coorY = maca.coorY;
pedaco[tamanho - 1].direcao = pedaco[tamanho - 2].direcao;
// reinicializando a posição da maçã
// escolhe uma posição diferente das peças da serpente
posiciona_maca();
}
/* Colisão só será atualizada no próximo loop, pois o usuário deve ver as peças sobrepostas */
if (colisao)
{
// reinicia o jogo e seta a variavel colisao para 0
inicia_jogo();
}
/* Colisão entre cabeça e outras partes da cobra */
for (i = 0; i < tamanho - 2 && colisao == 0; i++)
{
if ((pedaco[tamanho - 1].coorX == pedaco[i].coorX) &&
(pedaco[tamanho - 1].coorY == pedaco[i].coorY))
colisao = 1;
}
// Blitagem
// Pintando o tela de branco
SDL_FillRect(tela, NULL, SDL_MapRGB(tela->format, 255, 255, 255));
SDL_Rect destino;
destino.x = maca.coorX * TAMANHOIMAGEM;
destino.y = maca.coorY * TAMANHOIMAGEM;
SDL_BlitSurface(img_maca, NULL, tela, &destino);
desenha_snake();
// atualizando a tela
SDL_UpdateRect(tela, 0,0,0,0);
controla_fps(tempo_inicial);
}
SDL_Quit(); // fecha o SDL
return 0;
}
/* Funcao que controla o fps */
void controla_fps ( int tempo_inicial )
{
int fps = 1000/7; // converte 7 FPS para milissegundos
int tempo_agora = SDL_GetTicks() - tempo_inicial;
if(tempo_agora < fps)
SDL_Delay(fps - tempo_agora);
}
int carrega_imagens ( )
{
img_maca = SDL_LoadBMP("apple.bmp");
if (img_maca == NULL)
{
printf("Não carregou apple.bmp\n");
return 0;
}
img_snakes = SDL_LoadBMP("piece.bmp");
if (img_snakes == NULL)
{
printf("Não carregou piece.bmp\n");
return 0;
}
img_cabeca = SDL_LoadBMP("head.bmp");
if (img_cabeca == NULL)
{
printf("Não carregou head.bmp\n");
return 0;
}
return 1;
}
void posiciona_maca ( )
{
int i;
int repetir;
do
{
// escolhe aleatoriamente as coordenadas
maca.coorX = rand() % mapa_largura;
maca.coorY = rand() % mapa_altura;
repetir = 0;
for (i = 0; i < tamanho; i++)
{
// verifica em todas as peças se as coordenadas delas
// são iguais as novas coordenadas da maçã.
if ((pedaco[i].coorX == maca.coorX) && (pedaco[i].coorY == maca.coorY))
{
// Se forem iguais então pare o loop e
// repita o procedimento para escolher outra coordenada para a maçã.
repetir = 1;
break;
}
}
// enquanto for para repetir continue escolhendo outra coordenada para a maçã.
} while (repetir);
}
void controla_snake ( SDL_Event evento )
{
if (evento.type == SDL_KEYDOWN)
{
switch (evento.key.keysym.sym)
{
case SDLK_RIGHT:
seta_direita = 1;
break;
case SDLK_LEFT:
seta_esquerda = 1;
break;
case SDLK_UP:
seta_cima = 1;
break;
case SDLK_DOWN:
seta_baixo = 1;
break;
case SDLK_p:
velX = 0;
velY = 0;
break;
default:
break;
}
}
else if (evento.type == SDL_KEYUP)
{
switch (evento.key.keysym.sym)
{
case SDLK_RIGHT:
seta_direita = 0;
break;
case SDLK_LEFT:
seta_esquerda = 0;
break;
case SDLK_UP:
seta_cima = 0;
break;
case SDLK_DOWN:
seta_baixo = 0;
break;
default:
break;
}
}
}
void move_snake ( )
{
if (seta_direita && pedaco[tamanho - 1].direcao != ESQUERDA)
{
velX = 1; // move horizontalmente a cabeça para direita
velY = 0; // e para de mover verticalmente
pedaco[tamanho - 1].direcao = DIREITA;
}
else if (seta_esquerda && pedaco[tamanho - 1].direcao != DIREITA)
{
velX = -1; // move horizontalmente a cabeça para esquerda
velY = 0; // e para de mover verticalmente
pedaco[tamanho - 1].direcao = ESQUERDA;
}
else if (seta_cima && pedaco[tamanho - 1].direcao != BAIXO)
{
velX = 0; // para de mover horizontalmente
velY = -1; // e move verticalmente a cabeça
pedaco[tamanho - 1].direcao = CIMA;
}
else if (seta_baixo && pedaco[tamanho - 1].direcao != CIMA)
{
velX = 0; // para de mover horizontalmente
velY = 1; // e move verticalmente a cabeça
pedaco[tamanho - 1].direcao = BAIXO;
}
// depois ajustando as posições das outras peças (partes)
// primeiro move as partes do corpo
if (velX || velY) // se estiver movendo
{
int i;
for (i = 0; i < tamanho - 1; i++)
{
// faça a peça de trás (pedaco[i]) igual a peça da frente (pedaco[i + 1])
pedaco[i].coorX = pedaco[i + 1].coorX;
pedaco[i].coorY = pedaco[i + 1].coorY;
pedaco[i].direcao = pedaco[i + 1].direcao;
}
}
// agora move a cabeça
pedaco[tamanho - 1].coorX += velX;
pedaco[tamanho - 1].coorY += velY;
// Verifica os limites do movimento da cobra
// Para o eixo X
// se estiver além da largura da tela/mapa
if (pedaco[tamanho - 1].coorX >= mapa_largura)
{
// volte para posição coorX = 0
pedaco[tamanho - 1].coorX = 0;
}
else if (pedaco[tamanho - 1].coorX < 0) // se estiver além de 0
{
// volte para a posição da largura do mapa
pedaco[tamanho - 1].coorX = mapa_largura - 1;
}
// Para o eixo Y
if (pedaco[tamanho - 1].coorY >= mapa_altura)
{
pedaco[tamanho - 1].coorY = 0;
}
else if (pedaco[tamanho - 1].coorY < 0)
{
pedaco[tamanho - 1].coorY = mapa_altura - 1;
}
}
if (seta_direita && pedaco[tamanho - 1].direcao != ESQUERDA)
{
velX = 1; // move horizontalmente a cabeça para direita
velY = 0; // e para de mover verticalmente
pedaco[tamanho - 1].direcao = DIREITA;
}
else if (seta_esquerda && pedaco[tamanho - 1].direcao != DIREITA)
{
velX = -1; // move horizontalmente a cabeça para esquerda
velY = 0; // e para de mover verticalmente
pedaco[tamanho - 1].direcao = ESQUERDA;
}
else if (seta_cima && pedaco[tamanho - 1].direcao != BAIXO)
{
velX = 0; // para de mover horizontalmente
velY = -1; // e move verticalmente a cabeça
pedaco[tamanho - 1].direcao = CIMA;
}
else if (seta_baixo && pedaco[tamanho - 1].direcao != CIMA)
{
velX = 0; // para de mover horizontalmente
velY = 1; // e move verticalmente a cabeça
pedaco[tamanho - 1].direcao = BAIXO;
}

// Verifica os limites do movimento da cobra
// Para o eixo X
// se estiver além da largura da tela/mapa
if (pedaco[tamanho - 1].coorX >= mapa_largura)
{
// volte para posição coorX = 0
pedaco[tamanho - 1].coorX = 0;
}
else if (pedaco[tamanho - 1].coorX < 0) // se estiver além de 0
{
// volte para a posição da largura do mapa
pedaco[tamanho - 1].coorX = mapa_largura - 1;
}
void desenha_snake ( )
{
int i;
SDL_Rect destino;
// blitando as img_macas das peças
for (i = 0; i < tamanho - 1; i++)
{
destino.y = pedaco[i].coorY * TAMANHOIMAGEM;
destino.x = pedaco[i].coorX * TAMANHOIMAGEM;
SDL_BlitSurface(img_snakes, NULL, tela, &destino);
}
// blitando a cabeça
destino.y = pedaco[tamanho - 1].coorY * TAMANHOIMAGEM;
destino.x = pedaco[tamanho - 1].coorX * TAMANHOIMAGEM;
SDL_BlitSurface(img_cabeca, NULL, tela, &destino);
}
/*===== o loop principal =====*/
while (!fim)
{
tempo_inicial = SDL_GetTicks();
sprintf(hud, "SNAKE by Sam L. - TAMANHO: ATUAL = %d | ANTERIOR = %d", tamanho, tamanho_anterior);
SDL_WM_SetCaption(hud, NULL);
while (SDL_PollEvent(&evento))
{
if (evento.type == SDL_QUIT)
{
fim = 1;
break;
}
controla_snake(evento);
}
// move a cobra
move_snake();
// colisão com a maçã
if ((pedaco[tamanho - 1].coorX == maca.coorX) &&
(pedaco[tamanho - 1].coorY == maca.coorY))
{
tamanho++;
pedaco[tamanho - 1].coorX = maca.coorX;
pedaco[tamanho - 1].coorY = maca.coorY;
pedaco[tamanho - 1].direcao = pedaco[tamanho - 2].direcao;
// reinicializando a posição da maçã
// escolhe uma posição diferente das peças da serpente
posiciona_maca();
}
/* Colisão só será atualizada no próximo loop, pois o usuário deve ver as peças sobrepostas */
if (colisao)
{
// reinicia o jogo e seta a variavel colisao para 0
inicia_jogo();
}
/* Colisão entre cabeça e outras partes da cobra */
for (i = 0; i < tamanho - 2 && colisao == 0; i++)
{
if ((pedaco[tamanho - 1].coorX == pedaco[i].coorX) &&
(pedaco[tamanho - 1].coorY == pedaco[i].coorY))
colisao = 1;
}
// Blitagem
// Pintando o tela de branco
SDL_FillRect(tela, NULL, SDL_MapRGB(tela->format, 255, 255, 255));
SDL_Rect destino;
destino.x = maca.coorX * TAMANHOIMAGEM;
destino.y = maca.coorY * TAMANHOIMAGEM;
SDL_BlitSurface(img_maca, NULL, tela, &destino);
desenha_snake();
// atualizando a tela
SDL_UpdateRect(tela, 0,0,0,0);
controla_fps(tempo_inicial);
}
// colisão com a maçã
if ((pedaco[tamanho - 1].coorX == maca.coorX) &&
(pedaco[tamanho - 1].coorY == maca.coorY))
{
tamanho++;
pedaco[tamanho - 1].coorX = maca.coorX;
pedaco[tamanho - 1].coorY = maca.coorY;
pedaco[tamanho - 1].direcao = pedaco[tamanho - 2].direcao;
// reinicializando a posição da maçã
// escolhe uma posição diferente das peças da serpente
posiciona_maca();
}
/* Colisão só será atualizada no próximo loop, pois o usuário deve ver as peças sobrepostas */
if (colisao)
{
// reinicia o jogo e seta a variavel colisao para 0
inicia_jogo();
}
/* Colisão entre cabeça e outras partes da cobra */
for (i = 0; i < tamanho - 2 && colisao == 0; i++)
{
if ((pedaco[tamanho - 1].coorX == pedaco[i].coorX) &&
(pedaco[tamanho - 1].coorY == pedaco[i].coorY))
colisao = 1;
}// Blitagem // Pintando o tela de branco SDL_FillRect(tela, NULL, SDL_MapRGB(tela->format, 255, 255, 255)); SDL_Rect destino; destino.x = maca.coorX * TAMANHOIMAGEM; destino.y = maca.coorY * TAMANHOIMAGEM; SDL_BlitSurface(img_maca, NULL, tela, &destino); desenha_snake(); // atualizando a tela SDL_UpdateRect(tela, 0,0,0,0); controla_fps(tempo_inicial);
Desenhando fácil um pinguim no Inkscape
Dicas para aprender programação
A arte e a prática da Disciplina a longo prazo
Algoritmo Antissocial - Recuperando o Controle da sua Mente
Android NDK: Desmistificando o acesso a códigos nativos em C
GNA: um Coprocessador para Aceleração Neural
Tratamento de exceções na linguagem C
Desenvolvendo um plugin de visualização para o XMMS (Parte 1)
Modo Simples de Baixar e Usar o bash-completion
Monitorando o Preço do Bitcoin ou sua Cripto Favorita em Tempo Real com um Widget Flutuante
fusermount3 no Ubuntu 25.10 - mantenha o perfil do AppArmor
[Resolvido] dlopen(): error loading libfuse.so.2 AppImages require FUSE to run.
Criação de diretórios e aplicação de restrições de acesso no Linux
Como você configura seu GNOME? Eu faço assim... (4)
ClamAV, um montão de coisas suspeitas .... (0)









