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.668 ]
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);
Algoritmo Antissocial - Recuperando o Controle da sua Mente
A arte e a prática da Disciplina a longo prazo
Dicas para aprender programação
Estudando recursividade direta e indireta
Acessando a porta paralela via Linux
Como funcionam os alocadores de memória do STD C?
Instalando Facebook Folly através do Conan
Cirurgia para acelerar o openSUSE em HD externo via USB
Void Server como Domain Control
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
Atualizar Linux Mint 22.2 para 22.3 beta
Jogar games da Battle.net no Linux com Faugus Launcher
Como fazer a Instalação de aplicativos para acesso remoto ao Linux
Conky, alerta de temperatura alta (10)
Assisti Avatar 3: Fogo e Cinzas (3)
Duas Pasta Pessoal Aparecendo no Ubuntu 24.04.3 LTS (42)









