jogo Sokoban (com gráficos)
Publicado por Samuel Leonardo 22/03/2009 (última atualização em 10/12/2009)
[ Hits: 11.539 ]
Homepage: localhost
Download Game_Sokoban_0.2.tar.gz (versão 2)
Esse é mais um joguino feito por mim. Uma imitação, simples, de um jogo chamado Sokoban. Falta algumas coisas nele, mas fica como exemplo de algo que pode ser mais elaborado, só precisa usar a criatividade para isso :)
Acompanha uma versão pré-compilada para GNU/Linux, mas pode ser facilmente portada para windows.
Para compilar:
$ gcc -o sokoban sokoban.c -lSDL
Para executar:
$ ./sokoban
t+!
Versão 2 - Enviado por Samuel Leonardo em 09/11/2009
Changelog: - Correção da função Move() e adição de transparência na imagem do jogador.
Nota: o jogo ainda continua sem um fim
Download Game_Sokoban_0.2.tar.gz
/* Sam L. EM 21/03/2009 Esse é mais um joguino feito por mim. Uma imitação, simples, de um jogo chamado Sokoban. Falta algumas coisas nele, mas fica como exemplo de algo que pode ser mais elaborado, só precisa usar a criatividade para isso :) Acompanha uma versão pré-compilada para GNU/Linux, mas pode ser facilmente portada para windows. Para compilar: $ gcc -o sokoban sokoban.c -lSDL Para executar: $ ./sokoban t+! OBSERVE: O JOGO NÃO TEM FIM AINDA. */ #include <stdio.h> #include <SDL/SDL.h> /*POSIX*/ #ifndef WIN32 #include <unistd.h> #else #include <SDL/SDL_main.h> #include <windows.h> #endif //altura e largura das imagens, todas são de mesmas dimensões #define IMGS_HEIGHT 50 #define IMGS_WIDTH 50 #define MAP_WIDTH 8 #define MAP_HEIGHT 6 #define PAREDE 0 #define CAIXA 1 #define VOCE 2 #define CHAO 3 #define LUGARES_CAIXA 4 #define SCREEN_WIDTH (IMGS_WIDTH*MAP_WIDTH) #define SCREEN_HEIGHT (IMGS_HEIGHT*MAP_HEIGHT) #define BPP 16 SDL_Surface *screen, *player, *muro, *piso, *caixa, *lugares; SDL_Rect destino; //OBS: linha_atual = 2 e coluna_atual = 7, //significa que o jogador se encontra inicialmente na linha de indice 2 e coluna de indice 7 //poderia ser outros valores, contanto que o valor de mapa[linha_atual][coluna_atual] não seja uma PAREDE nem uma CAIXA int linha_atual = 2, coluna_atual = 7, fim = 0; /* Mapa */ int mapa[MAP_HEIGHT][MAP_WIDTH]={ {0,0,3,3,3,0,0,0},//linha 0 {3,3,3,1,3,1,3,3}, {3,1,3,3,3,1,3,3}, {0,0,1,1,0,0,0,0}, {0,0,3,3,3,3,0,0}, {0,0,3,3,3,3,0,0}//linha 5 }; //Isso evita que que as imagens dos lugares desapareça //Aqui é como se fosse uma segunda camada, só para colagem de imagens por baixo das outras //exemplo: CHAO por baixo de VOCE(player), LUGARES_CAIXA por debaixo de CAIXA int sub_imgs[MAP_HEIGHT][MAP_WIDTH]= { {0,0,3,3,3,0,0,0}, {3,3,3,3,3,3,3,3}, {3,3,3,3,3,3,3,3}, {0,0,3,3,0,0,0,0}, {0,0,3,3,4,4,0,0}, {0,0,4,4,4,4,0,0} }; /*===============FUNCOES================*/ //controla o fps do jogo void Limita_fps(int tempo) { tempo = SDL_GetTicks() - tempo; if(tempo < 30) SDL_Delay(30 - tempo); } //converte e carrega as imagens no mesmo formato da tela SDL_Surface *FuncLoad(const char *filename) { SDL_Surface *tmp, *surf; tmp = SDL_LoadBMP(filename); if(!tmp) { printf("ERROR: %s\n",SDL_GetError()); return NULL; } surf = SDL_DisplayFormat(tmp); SDL_FreeSurface(tmp); return surf; } //carrega as imagens void Load_imgs(void) { player = FuncLoad("imagens/jogador.bmp"); muro = FuncLoad("imagens/parede.bmp"); caixa = FuncLoad("imagens/caixa.bmp"); lugares = FuncLoad("imagens/lugares.bmp"); piso = FuncLoad("imagens/piso.bmp"); } //descarregas as surfaces void UnLoad_imgs(void) { SDL_FreeSurface(player); SDL_FreeSurface(muro); SDL_FreeSurface(caixa); SDL_FreeSurface(lugares); SDL_FreeSurface(piso); } //controla o jogador, aqui é uma parte muito importante //pois nela tamb está contida a "verificação de colisão" void Move() { /* Controles do jogador */ Uint8 *teclado; SDL_PumpEvents(); teclado = SDL_GetKeyState(0); /* Para terminar o jogo */ if(teclado[SDLK_ESCAPE]) { fim = 1; return; } /* Modo FullScreen, opcional */ if(teclado[SDLK_f]) { SDL_WM_ToggleFullScreen(screen); } /*=============== Deslocamento do jogador =====================*/ /* Vertical */ /* Se o usuario aperta a seta para cima e linha_atual for maior que 0 ... */ if((teclado[SDLK_UP]) && (linha_atual > 0)) { /* 0 = primeira linha */ /* ...subtraia 1 de linha_atual, ou seja, suba uma linha... */ linha_atual = linha_atual - 1; /*OBSERVE: aqui é a colisão, SE O USUARIO ESTIVER MOVENDO PARA CIMA*/ /* A LÓGICA FUNCIONA MAIS OU MENOS ASSIM: --SE O USER APERTAR PARA CIMA E A LINHA ATUAL DO PERSONAGEM NÃO FOR MAIOR QUE O LIMITE SUPERIOR DO CAMPO, linha_atual > 0 --FAÇA: ------MOVA O PERSONAGEM UMA LINHA A MENOS, linha_atual = linha_atual - 1; ------AGORA VERIFIQUE NO MAPA SE ESSA "linha_atual - 1" COM "coluna_atual", É UM OBJETO(caixa, parede) ------SE FOR UMA CAIXA --------E SE NA LINHA ANTERIOR A "linha_atual" DA CAIXA COM "coluna_atual" DA CAIXA, NO MAPA, FOR IGUAL À CHÃO --------E "linha_atual" FOR DIFERENTE DE ZERO...(ufa!) --------FAÇA: ------------POSIÇÃO ATUAL DA CAIXA NO MAPA IGUAL A "CHÃO", mapa[linha_atual][coluna_atual] = CHAO; ------------NOVA POSIÇÃO DA CAIXA NO MAPA IGUAL A "CAIXA", mapa[linha_atual - 1][coluna_atual] = CAIXA; --MAS SE O USER MOVE O PERSONAGEM PARA CIMA, uma linha_atual a menos, E ELE FICA SOBRE UM OBJETO(caixa,parede); --FAÇA: ------MOVA O PERSONAGEM UMA LINHA A MAIS, OU SEJA, RETORNE AO VALOR ANTERIOR AO DO MOVIMENTO EXISTE MAIS UM SCRIPT QUE USA A MESMA LÓGICA: http://vivaolinux.com.br/script/1o.-joguinho-Labirinto-(com-graficos).c E UM VIA LINHA DE COMANDO, BEM MAIS FÁCIL DE COMPREENDER http://www.vivaolinux.com.br/scripts/verFonte.php?codigo=722 */ if((mapa[linha_atual][coluna_atual] == CAIXA)&& ((mapa[linha_atual - 1][coluna_atual] == CHAO) || (linha_atual != 0))) { mapa[linha_atual][coluna_atual] = CHAO; mapa[linha_atual - 1][coluna_atual] = CAIXA; } if(mapa[linha_atual][coluna_atual] == CAIXA) { linha_atual = linha_atual + 1;//ou linha_atual += 1 ou linha_atual++, tanto faz } if(mapa[linha_atual][coluna_atual] == PAREDE) { linha_atual = linha_atual + 1; } //Aqui não é necessário verificar se está apertando //mais de um botão ao mesmo tempo, então retorne return; } /* A mesma logica a cima, muda mto poco :) */ if((teclado[SDLK_DOWN]) && (linha_atual < 5)) { /* 9 = ultima linha */ linha_atual = linha_atual + 1; if((mapa[linha_atual][coluna_atual] == CAIXA)&& ((mapa[linha_atual + 1][coluna_atual] == CHAO) || (linha_atual != 6))) { mapa[linha_atual][coluna_atual] = CHAO; mapa[linha_atual + 1][coluna_atual] = CAIXA; printf("coluna:%i,linha:%d\n", coluna_atual, linha_atual); } if(mapa[linha_atual][coluna_atual] == CAIXA) { linha_atual = linha_atual - 1; } if(mapa[linha_atual][coluna_atual] == PAREDE) { linha_atual = linha_atual - 1; } //Aqui não é necessário verificar se está apertando //mais de um botão ao mesmo tempo, então retorne return; } /* Horizontal */ /* Se o usuario aperta a seta para esquerda e coluna_atual for maior que 0 ... */ if((teclado[SDLK_LEFT]) && (coluna_atual > 0)) { /* 0 = primeira coluna */ /* ...subtraia 1 de coluna_atual, ou seja, recue uma coluna ... */ coluna_atual -= 1; if((mapa[linha_atual][coluna_atual] == CAIXA)&& ((mapa[linha_atual][coluna_atual - 1] == CHAO) || (coluna_atual != 0))) { mapa[linha_atual][coluna_atual] = CHAO; mapa[linha_atual][coluna_atual - 1] = CAIXA; printf("coluna:%i,linha:%d\n", coluna_atual, linha_atual); } if(mapa[linha_atual][coluna_atual] == CAIXA) { coluna_atual = coluna_atual + 1; } if(mapa[linha_atual][coluna_atual] == PAREDE) { coluna_atual = coluna_atual + 1; } //Aqui não é necessário verificar se está apertando //mais de um botão ao mesmo tempo, então retorne return; } /* A mesma logica a cima, muda mto poco :) */ if((teclado[SDLK_RIGHT]) && (coluna_atual < 7)) { coluna_atual = coluna_atual + 1; if((mapa[linha_atual][coluna_atual] == CAIXA)&& ((mapa[linha_atual][coluna_atual + 1] == CHAO) || (coluna_atual != 7))) { mapa[linha_atual][coluna_atual] = CHAO; mapa[linha_atual][coluna_atual + 1] = CAIXA; printf("coluna:%i,linha:%d\n", coluna_atual, linha_atual); } if(mapa[linha_atual][coluna_atual] == CAIXA) { coluna_atual = coluna_atual - 1; } if(mapa[linha_atual][coluna_atual] == PAREDE) { coluna_atual = coluna_atual - 1; } } } //Função que "desenhará" as imagens na tela void Draw_map() { int linha, coluna; for(linha=0; linha < MAP_HEIGHT; linha++) { destino.y = linha*IMGS_HEIGHT; for(coluna=0; coluna < MAP_WIDTH; coluna++) { destino.x = coluna*IMGS_WIDTH; switch(sub_imgs[linha][coluna]) { case CHAO: SDL_BlitSurface(piso, NULL, screen, &destino); break; case LUGARES_CAIXA: SDL_BlitSurface(lugares, NULL, screen, &destino); break; default: break; } switch(mapa[linha][coluna]) { case PAREDE: SDL_BlitSurface(muro, NULL, screen, &destino); break; case CAIXA: SDL_BlitSurface(caixa, NULL, screen, &destino); break; default: break; } //Aqui seria VOCE if((linha == linha_atual) && (coluna == coluna_atual)) { destino.y = linha*IMGS_HEIGHT; destino.x = coluna*IMGS_WIDTH; SDL_BlitSurface(player, NULL, screen, &destino); } } } } void Instrucoes(void) { printf("\t Bem vindo! ao: \nGame Sokoban\n"); printf("Seu objetivo é levar todos as caixas até os pontos marcados com circulos,\n por enquanto esta versão tem somente uma fase :P,\n é fácil melhorá-lo, mas é você que terá que fazer :)\n"); printf("\nCONTROLES:\n|botão | função |\n"); printf("botão-'f' | Tela em Modo FullScreen\n"); printf("botão-'Esc'| Termina o jogo\n"); printf("setas | Controlam o personagem\n"); } int main(int argc, char *argv[]) { int tempo_agora; Instrucoes(); SDL_Init(SDL_INIT_VIDEO); screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, BPP, SDL_SWSURFACE | SDL_DOUBLEBUF); destino = (SDL_Rect){0, 0, IMGS_WIDTH, IMGS_HEIGHT}; Load_imgs(); SDL_Event evento; SDL_WM_SetCaption("Game_Sokoban -> By Sam L.", NULL); while(!fim) { tempo_agora = SDL_GetTicks(); while(SDL_PollEvent(&evento)) { switch(evento.type) { case SDL_KEYDOWN: Move(); break; case SDL_QUIT: fim = 1; break; default: break; } } SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255)); Draw_map(); SDL_UpdateRect(screen,0,0,0,0); Limita_fps(tempo_agora); } UnLoad_imgs(); SDL_Quit(); return 0; }
Gerenciamento de Área de Alocação Dinâmica (Listas Encadeadas)
Jogo da Velha com IA invencivel
Cálculo de logaritmo de um número por um terceiro método em C
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Meu Fork do Plugin de Integração do CVS para o KDevelop
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Compartilhamento de Rede com samba em modo Público/Anônimo de forma simples, rápido e fácil
Cups: Mapear/listar todas as impressoras de outro Servidor CUPS de forma rápida e fácil
Criando uma VPC na AWS via CLI