jogo Sokoban (com gráficos)

Publicado por Samuel Leonardo 22/03/2009 (última atualização em 10/12/2009)

[ Hits: 11.518 ]

Homepage: localhost

Download Game_Sokoban.tar.gz

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ões atualizadas deste script

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


Esconder código-fonte

/*
  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;
}

Scripts recomendados

Jogo de 21 em C

Gerador de number list v2

Calculando PI usando série de Leibniz

Pilhas C/C++ - Analisador de expressões simples

Rotação à esquerda árvore Binária


  

Comentários
[1] Comentário enviado por SamL em 22/03/2009 - 01:14h

///corrigido no script versão 2

[2] Comentário enviado por pothix em 23/03/2009 - 11:40h

[PotHix Game_Sokoban]$ gcc -o sokoban sokoban.c -lSDL
sokoban.c:18:21: error: SDL/SDL.h: No such file or directory
sokoban.c:45: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
sokoban.c:46: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘destino’
sokoban.c:85: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
sokoban.c: In function ‘Load_imgs’:
sokoban.c:102: error: ‘player’ undeclared (first use in this function)
sokoban.c:102: error: (Each undeclared identifier is reported only once
sokoban.c:102: error: for each function it appears in.)
sokoban.c:103: error: ‘muro’ undeclared (first use in this function)
sokoban.c:104: error: ‘caixa’ undeclared (first use in this function)
sokoban.c:105: error: ‘lugares’ undeclared (first use in this function)
sokoban.c:106: error: ‘piso’ undeclared (first use in this function)
sokoban.c: In function ‘UnLoad_imgs’:
sokoban.c:112: error: ‘player’ undeclared (first use in this function)
sokoban.c:113: error: ‘muro’ undeclared (first use in this function)
sokoban.c:114: error: ‘caixa’ undeclared (first use in this function)
sokoban.c:115: error: ‘lugares’ undeclared (first use in this function)
sokoban.c:116: error: ‘piso’ undeclared (first use in this function)
sokoban.c: In function ‘Move’:
sokoban.c:124: error: ‘Uint8’ undeclared (first use in this function)
sokoban.c:124: error: ‘teclado’ undeclared (first use in this function)
sokoban.c:128: error: ‘SDLK_ESCAPE’ undeclared (first use in this function)
sokoban.c:134: error: ‘SDLK_f’ undeclared (first use in this function)
sokoban.c:136: error: ‘screen’ undeclared (first use in this function)
sokoban.c:141: error: ‘SDLK_UP’ undeclared (first use in this function)
sokoban.c:190: error: ‘SDLK_DOWN’ undeclared (first use in this function)
sokoban.c:218: error: ‘SDLK_LEFT’ undeclared (first use in this function)
sokoban.c:246: error: ‘SDLK_RIGHT’ undeclared (first use in this function)
sokoban.c: In function ‘Draw_map’:
sokoban.c:277: error: ‘destino’ undeclared (first use in this function)
sokoban.c:284: error: ‘piso’ undeclared (first use in this function)
sokoban.c:284: error: ‘screen’ undeclared (first use in this function)
sokoban.c:287: error: ‘lugares’ undeclared (first use in this function)
sokoban.c:296: error: ‘muro’ undeclared (first use in this function)
sokoban.c:299: error: ‘caixa’ undeclared (first use in this function)
sokoban.c:309: error: ‘player’ undeclared (first use in this function)
sokoban.c: In function ‘main’:
sokoban.c:332: error: ‘SDL_INIT_VIDEO’ undeclared (first use in this function)
sokoban.c:334: error: ‘screen’ undeclared (first use in this function)
sokoban.c:334: error: ‘SDL_SWSURFACE’ undeclared (first use in this function)
sokoban.c:334: error: ‘SDL_DOUBLEBUF’ undeclared (first use in this function)
sokoban.c:336: error: ‘destino’ undeclared (first use in this function)
sokoban.c:336: error: ‘SDL_Rect’ undeclared (first use in this function)
sokoban.c:336: error: expected ‘;’ before ‘{’ token
sokoban.c:340: error: ‘SDL_Event’ undeclared (first use in this function)
sokoban.c:340: error: expected ‘;’ before ‘evento’
sokoban.c:346: error: ‘evento’ undeclared (first use in this function)
sokoban.c:350: error: ‘SDL_KEYDOWN’ undeclared (first use in this function)
sokoban.c:354: error: ‘SDL_QUIT’ undeclared (first use in this function)

[3] Comentário enviado por SamL em 23/03/2009 - 11:47h

Olá potihx, os vários erros acima são causados por que você não tem instalado os arquivos de desenvolvimento da lib SDL.
Caso queira instalar eles, baixe-os aqui:
http://www.libsdl.org/download-1.2.php
vlw!

[4] Comentário enviado por SamL em 12/06/2009 - 22:17h

.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts