Conheça a iniciativa da Biblioteca dos Desenvolvedores  
Índice da Biblioteca  
Área dos Usuários  
Fórum de Discussão  
Forúm
 
  Cenário em Arquivos
Cenário em Arquivos

Esse artigo tem como objetivo mostrar como carregar várias fases de um jogo através de arquivos textos. Com certeza existem muitas outras maneiras de se fazer isso, mas aqui irei exemplificar uma forma simples e fácil de entender.

Com base nessas informações você poderá montar a sua própria maneira de organizar as fases do seu jogo.

Arquivo de Fases

Fase 1

Fase 2

Fase 3

####################
#..................#
#.........########.#
###########........#
#..................#
#.........##########
#.#########........#
#..................#
#.........########.#
###########........#
#..................#
#.........##########
#.#########........#
#..................#
####################

####################
#------------------#
#-###-###--###-###-#
#------------------#
#-###-###--###-###-#
#------------------#
#-###-###--###-###-#
#------------------#
#-###-###--###-###-#
#------------------#
#-###-###--###-###-#
#------------------#
#-###-###--###-###-#
#------------------#
####################

####################
#..................#
#.#.######.#####.#.#
#.#..............#.#
#.#.###.####.###.#.#
#...#..........#...#
#.#.#.########.#.#.#
#..................#
#.#.#.########.#.#.#
#...#..........#...#
#.#.###.####.###.#.#
#.#..............#.#
#.#.#####.######.#.#
#..................#
####################


Abaixo vamos apresentar as texturas utilizadas e o resultado final do cenário montado.

Texturas

Parede

Grama

Chão

Representação

Representação

Representação

# (Sustenido)

- (Traço)

. (Ponto)

 


Resultado Final

Fase 1

Fase 2

Fase 3

 

 

A parte mais importante do código é a função CarregaMatriz() que vamos explicar logo abaixo.
O restante do código você, obrigatoriamente, já deve estar familiarizado se estiver acompanhando os tutoriais anteriores.

Adotamos o tamanho da tela como sendo 640x480 e os tiles terão 32pixels de altura e largura.
Dessa forma teremos 20 tiles na horizontal e 15 tiles na vertical.

Se houver dúvida faça: 640/32 = 20 tiles na horizontal e 480/32 = 15 tiles na vertical.


No código de exemplo usei uma matriz tridimensional onde o primeiro string identifica a fase os outros 2 identificam a quantidade de tiles na horizontal e na vertical.

A ilustração abaixo se trata de uma visão da matriz referente à primeira fase. Onde a cor azul identifica a fase, a cor amarela identifica os tiles na horizontal e a cor laranja identifica os tiles na vertical. Observe bem o gráfico abaixo para poder entender a forma de ler o arquivo mais adiante.

 

C0

C1

C2

C3

C4

C5

C6

C7

C8

C9

C10

C11

C12

C13

C14

C15

C16

C17

C18

C19

1

L0

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

L1

#

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

#

L2

#

.

.

.

.

.

.

.

.

.

#

#

#

#

#

#

#

#

.

#

L3

#

#

#

#

#

#

#

#

#

#

#

.

.

.

.

.

.

.

.

#

L4

#

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

#

L5

#

.

.

.

.

.

.

.

.

.

#

#

#

#

#

#

#

#

#

#

L6

#

.

#

#

#

#

#

#

#

#

#

.

.

.

.

.

.

.

.

#

L7

#

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

#

L8

#

.

.

.

.

.

.

.

.

.

#

#

#

#

#

#

#

#

.

#

L9

#

#

#

#

#

#

#

#

#

#

#

.

.

.

.

.

.

.

.

#

L10

#

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

#

L11

#

.

.

.

.

.

.

.

.

.

#

#

#

#

#

#

#

#

#

#

L12

#

.

#

#

#

#

#

#

#

#

#

.

.

.

.

.

.

.

.

#

L13

#

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

#

L14

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#

#


Note que você sabe que obrigatoriamente a quantidade de tiles na largura tem que ser 20, então, levando em conta essa informação vamos criar uma variável do tipo char chamada “sLinha” com 20 posições de caracteres.

char sLinha[20];

Apenas para entendimento, se agente atribuir o texto “BDJogos” para a string acima o resultado vai ser o seguinte:

 

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

sLinha

B

D

J

o

g

o

s

\n

 

 

 

 

 

 

 

 

 

 

 

 



Até aqui você obrigatoriamente deve entender que se pegarmos a posição sLinha[0] o valor que ela deve retornar é B, sLinha[1] = D ... E assim sucessivamente.

É dessa forma que vamos preencher a matriz com os caracteres do arquivo texto.
Como nossa matriz é tridimensional e, nesse caso, iremos carregar todas as fases de uma vez só na matriz para posteriormente montar o cenário, devemos ter 3 sequências de repetição FOR.

Uma para a fase, uma para os tiles na horizontal e uma para os tiles na vertical.

Entre uma fase e outra iremos carregar o arquivo de fase para leitura e entre uma linha e outra iremos preencher a matriz.

O modo que a função preenche a matriz segue da esquerda para a direita e de cima para baixo.
Posiciona no Y, e varre o X atribuindo os valores na matriz[iFase][x][y]. Execute o código de exemplo para entender melhor.

Após entender a função CarregaMatriz() a função para desenhar as texturas na tela é fácil.
Precisamos apenas interpretar os caracteres nos arquivos e substituí-los por um objeto ou textura.

Para o código abaixo funcionar dentro da pasta do seu projeto você deve ter uma pasta chamada “fases” e outra chamada “tiles”. Dentro de cada uma você coloca seus respectivos arquivos de fases e imagens que vão utilizar na montagem do cenário. 

Segue a tela abaixo para exemplificar a disposição dos arquivos dentro da pasta do seu projeto.



Chega de teoria. Abaixo, segue o código para carregar 3 tipos de cenários diferentes.



CÓDIGO...
001:
002:
003:
004:
005:
006:
007:
008:
009:
010:
011:
012:
013:
014:
015:
016:
017:
018:
019:
020:
021:
022:
023:
024:
025:
026:
027:
028:
029:
030:
031:
032:
033:
034:
035:
036:
037:
038:
039:
040:
041:
042:
043:
044:
045:
046:
047:
048:
049:
050:
051:
052:
053:
054:
055:
056:
057:
058:
059:
060:
061:
062:
063:
064:
065:
066:
067:
068:
069:
070:
071:
072:
073:
074:
075:
076:
077:
078:
079:
080:
081:
082:
083:
084:
085:
086:
087:
088:
089:
090:
091:
092:
093:
094:
095:
096:
097:
098:
099:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
#include <allegro.h>
#include <iostream>
#include <fstream>

using namespace std;

int fps = 0;
int fps_antigo = 0;
int fps_speed = 0;

// prototipo do contador de frames
void frame_rate();

// prototipo do contador de velocidade 
void incrementa_speed();

void Teclado();
void CarregaMatriz();
void CarregaTexturas();
void DesenhaCenario(BITMAP *, int );

//A variável abaixo guarda o local onde estão as fases em arquivo texto.
const char *ArqFases[] = {"fases/fase1.txt""fases/fase2.txt""fases/fase3.txt"};

const int iQtdeFases = 3;    // Jogo com 3 fases
const int iTamTilesX = 32;   // Largura do Tile
const int iTamTilesY = 32;   // Altura do Tile
const int iTilesX =  20;      // Qtde de Tiles na horizontal - 32*20 = 640;
const int iTilesY = 15;      // Qtde de Tiles na vertical   - 32*15 = 480;
/*
Com base nas variáveis acima temos o tamanho da tela 640x480, conforme abaixo: 
   (iTamTilesX * iTilesX) = SCREEN_W;
   (iTamTilesY * iTilesY) = SCREEN_H;
   (32 * 20) = 640;
   (32 * 15) = 480;
*/


int iFaseAtual = 0; // Guarda o index da fase atual.

//Variável do tipo BITMAP responsável por guardar as texturas
BITMAP *Textura[3] = {NULL, NULL, NULL};

/*  
Variáveis Mapa tridimensional sendo o primeiro ecrãn a Fase e os 
outros dois correspondem a quantidade de Tiles na horizontal e vertical.
*/

int Mapa[iQtdeFases][iTilesX][iTilesY];

int main()
{
   allegro_init();
   install_keyboard();
   set_color_depth(32);
   set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
   set_window_title( "Fases em arquivos textos" );

   install_timer();
   install_int( frame_rate, 1000 );
   install_int_ex( incrementa_speed, BPS_TO_TIMER(60) );

   //Habilita Acentuação
   set_uformat(U_ASCII);

   BITMAP *Buffer = NULL;
   Buffer = create_bitmap(SCREEN_W, SCREEN_H);

   CarregaMatriz();
   CarregaTexturas();

   while (!key[KEY_ESC])
   {
      while ( ::fps_speed > 0 ) 
      { 
         clear_bitmap(Buffer);
         DesenhaCenario(Buffer, iFaseAtual);
         Teclado();

         textprintf_ex( Buffer, font, 8, 10, makecol(255,255,0)-1, "FPS: %d"::fps_antigo );
         textprintf_centre_ex(Buffer, font, SCREEN_W/2, (SCREEN_H/2)-10, makecol(255, 255, 0),
         -1, "FASE: %d", iFaseAtual+1);
         textprintf_centre_ex(Buffer, font, SCREEN_W/2, SCREEN_H/2, makecol(255, 255, 0)-1, 
         "Pressione espaço para mudar de fase.");

         ::fps_speed--;
         ::fps++;
      }
      blit (Buffer,screen, 0, 0, 0, 0,SCREEN_W, SCREEN_H);
      vsync();
   }

   //Desaloca as imagens da memória
   destroy_bitmap(Buffer);
   destroy_bitmap(Textura[0]);
   destroy_bitmap(Textura[1]);
   destroy_bitmap(Textura[2]);
   allegro_exit();

   return 0;
}
/*
A função abaixo é a mais importante com relação ao arquivo de fases. Ela serve 
para carregar os valores que estão dentro do arquivo de fase para a matriz. 
Com base na matriz iremos montar o cenário de cada fase e posicionar suas 
respectivas texturas ou objetos, dependendo de como você modificar o código.
*/

void CarregaMatriz()
{
   int x = 0;
   int y = 0;
   int iFase = 0;

   char sLinha[ iTilesX ]; // Qtde de caracteres por linha

   //O FOR abaixo é para preencher todas as fases.
   for (iFase=0; iFase<iQtdeFases; iFase++)
   {
      // Abre o arquivo de fases para leitura com base no iFase e o Array de fases
      ifstream oLendoFase(ArqFases[iFase], ios::in );    

      //Preenche a matriz na horizontal e vertical
      for (y=0; y<iTilesY; y++)
      {   
         /*
         Atribui na variável sLinha a linha atual do arquivo texto.
         Toda vez que essa rotina for chamada ele pula para a proxima linha e
         joga o valor para sLinha, até finalizar as 15 linhas.
         */

         oLendoFase >> sLinha;

         /*
            Já com o sLinha preenchido, agora, o FOR abaixo varre todas as 
            posições dessa linha e acrescenta na linha da matriz. Após terminar
            de varrer o sLinha sai do for e espera próxima linha, se houver.
         */

         for (x=0; x<iTilesX; x++)
         {
            
            Mapa[iFase][x][y] = sLinha[x];
         }
      }
      oLendoFase.close();
   }
}
/*
A função abaixo é responsável por declarar e definir as imagens que iremos
utilizar no Array Textura. Essa imagens devem estar dentro da pasta imagens no 
nosso projeto,caso contrário o programa irá apresentar a mensagem de erro fatal.
*/

void CarregaTexturas()
{
   // Define o índice 0 da textura como sendo parede
   Textura[0] = create_bitmap(iTamTilesX, iTamTilesY);
   Textura[0] = load_bitmap("tiles/parede.bmp", NULL);
   
   // Define o índice 1 da textura como sendo grama
   Textura[1] = create_bitmap(iTamTilesX, iTamTilesY);
   Textura[1] = load_bitmap("tiles/grama.bmp",NULL);

   // Define o índice 2 da textura como sendo chão
   Textura[2] = create_bitmap(iTamTilesX, iTamTilesY);
   Textura[2] = load_bitmap("tiles/chao.bmp",NULL);
}

/*
Essa função é responsável por desenhar as texturas do cenário. O cenário a ser 
carregado é informado através de um argumento. Essa função usa como base a matriz
carregada anteriormente para desenhar as texturas.
*/

void DesenhaCenario(BITMAP *Cenario, int iFase)
{
   int x = 0;
   int y = 0;

   for (y=0; y<iTilesY; y++)
   {
      for (x=0; x<iTilesX; x++)
      {
         if  ((char)Mapa[iFase][x][y] == '#') // Parede
            draw_sprite(Cenario,Textura[0], x*iTamTilesX, y*iTamTilesY);
         else
         if  ((char)Mapa[iFase][x][y] == '-') // Grama
            draw_sprite(Cenario,Textura[1], x*iTamTilesX, y*iTamTilesY);
         else
         if  ((char)Mapa[iFase][x][y] == '.') // Chão
            draw_sprite(Cenario,Textura[2], x*iTamTilesX, y*iTamTilesY);
      }
   }
}
/*
A função abaixo é responsável por controlar as entradas do teclado, qualquer
tecla pressionada durante a execução do jogo.
*/

void Teclado()
{
   /*
   Quando declaramos uma variável como sendo static quer dizer que mesmo saindo
   da função ela não vai perder o valor dela. Dessa forma, utilizamos a variável 
   abaixo para controlar o tempo de uma tecla a outra.
   */

   static int Buffer_Teclado = 0;

   //Tudo que estiver dentro o IF abaixo será executado a cada 30 ciclos de CPU
   if (Buffer_Teclado == 0)
   {
      // Muda o Cenário caso aperte a tecla espaço
      if (key[KEY_SPACE])
      {
         if (iFaseAtual < (iQtdeFases-1))
            iFaseAtual++;
         else
            iFaseAtual = 0;
         
         Buffer_Teclado = 30;
      }
   } else Buffer_Teclado--;
}

void frame_rate()
{
   ::fps_antigo = ::fps;
   ::fps = 0;
}
   
void incrementa_speed()
{
   ::fps_speed++; 
}
END_OF_MAIN();

FIM DE CÓDIGO...



Ao executar o código acima você irá perceber que ele mostra apenas um cenário montado. Aperte a barra de espaço para mostrar os demais cenários.

De qualquer forma, você já consegue fazer um jogo de puzzle com vários cenários carregados a partir de um arquivo de dados.
Mais adiante após estudar mais sobre organização de cenários dentro de arquivos, estarei disponibilizando mais materiais sobre o assunto.

Para melhor entendimento do código acima compile, execute e altere o código como bem entender. Quaisquer dúvidas estaremos no fórum para tentar ajudar.

Abraço.


Contribuidor
Bruno A. Rovela
10/06/2008

Voltar

 
 

01/06/2007 (C) Copyright. Todos os Direitos Reservados. Leia a política de privacidade do portal.
É proibida a cópia de conteúdo deste site de acordo com a Lei Brasileira de Direitos Autorais.