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: 25.908 ]
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);
Dicas para aprender programação
Algoritmo Antissocial - Recuperando o Controle da sua Mente
Desenhando fácil um pinguim no Inkscape
Algum humor e C++ Design Patterns (parte 2)
Cuidado com números em Ponto Flutuante
Criando aplicativos para o iPhone no Linux (sem Xcode e MacOS X)
Como gerar qualquer emoji ou símbolo unicode a partir do seu teclado
Instalar e Configurar o Slackware Linux em 2025
Como configurar os repositórios do apt no Debian 12 em 2025
Passkeys: A Evolução da Autenticação Digital
Instalação de distro Linux em computadores, netbooks, etc, em rede com o Clonezilla
Muitas dificuldades ao instalar distro Linux em Notebook Sony Vaio PCG-6131L (VPCEA24FM)
Slackpkg+ (Slackpkg Plus) está de volta!
Como dividir duas janelas igualmente e lado-a-lado na sua tela
Configurando o Conky para iniciar corretamente no sistema
3 configurações básicas que podem melhorar muito a sua edição pelo editor nano
Erro de segmentação «Segmentation fault (core dumped)» ao retornar obj... (4)
Não Consigo instalar o cli-visualizer no Ubuntu 24.04 (2)
compilação samba 4.22 rock linux 9.5 (1)
Posso instalar usar o grub sem ter linux instalado, para iniciar o win... (1)
Ocomon 6.0.1 - Problemas ao editar configurações estendidas (4)