Curso completo de DarkGdk
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
Fase 17.1

index << >>



17.1 Salvando e recuperando dados

1.1 Visão geral


Neste tópico vamos ver como salvar e recuperar dados que é um processo típico 
de diversas situações como salvar e carregar o status de uma sessão do jogo,
para produzir e recuperar dados em formato próprio como uma mapa de jogo.

Relembramos que existe outros dois caminhos de gravar e recuperar dados em
arquivos que você pode usar para complementar  ou  substituir a  DarkGdk
que neste aspecto apresenta algumas inconsistências na versão aqui utilizada.
Você pode usar as funções de entrada e  saída da  biblioteca  padrão  da 
linguagem c/c++ e da biblioteca do Windows.

Neste tópico vamos estudar as seguintes funções de gravação:
---------------------------------------------------------------------------
dbOpenToWrite()	- Cria e abre um arquivo para gravação			
dbFileOpen()	- Verifica o sucesso da abertura de arquivo
dbWriteString()	- Grava uma string no arquivo aberto
dbWriteLong()	- Grava um (long) valor de 32 bits no arquivo
dbWriteWord ()	- Grava um (word) valor de 16 bits no arquivo	
dbWriteByte()	- Grava um (byte) valor de 8 bits no arquivo
dbCloseFile()	- Fecha o arquivo que foi aberto em modo leitura ou gravação

As funções de gravação acima apresentam as respectivas contraparte de leitura:
---------------------------------------------------------------------------
dbOpenToRead()	- Abre um arquivo para leitura
dbReadString()	- Lê uma string no arquivo aberto
dbReadLong()	- Lê um (long) valor de 32 bits do arquivo
dbReadWord ()	- Lê um (word) valor de 16 bits do arquivo	
dbReadByte()	- Lê um (byte) valor de 8 bits do arquivo

A função dbReadString() não será estudada pois não está funcionando adequadamente.
Em seu lugar será utilizada a função dbReadByte().


1.1.1 Ponteiro interno É importante saber que o arquivo em disco tem um endereço, tem uma posição específica aonde ele está gravado. Nos bastidores do processo de gravação e leitura é criado um ponteiro que aponta para esta posição e qualquer operação de gravação e leitura provoca um deslocamento neste ponteiro determinando aonde vai ocorrer a próxima leitura/gravação de dados. Dado então a existência do ponteiro é necessário ficar atento ao tamanho, quantidade e na ordem dos dados que serão lidos ou gravados. Um descontrole nestes aspectos pode ocasionar discrepâncias na recuperação dos mesmos, pode ocasionar falta de correspondência do dado gravado com o dado lido. Segue abaixo algumas nomenclaturas e tamanho dos tipos de dados básicos: nibble 4 bits byte 8 bits ou dois nibbles char 1 byte word 2 bytes long 4 bytes (*) int 4 bytes (*) * O tamanho de alguns tipos pode variar conforme o sistema e/ou compilador sendo usados. Você pode checar o tamanho em tempo real usando o operador sizeof() da linguagem c/c++.
1.2 Estudo das funções de leitura e gravação dbOpenToWrite(hfile, sArquivo) void dbOpenToWrite ( int f, char* pFilename ); Esta função cria um arquivo e o abre para gravação. Esta função falha se o arquivo existir de forma que você deve deletá-lo e recriá-lo para ter sucesso nos processos de gravação. Você deve verificar o sucesso da abertura do arquivo com a função dbFileOpen(). hfile - valor que indentifica o arquivo em processsos posteriores sArquivo - nome do arquivo a ser aberto Ex.: int hfile = 6; char *sArquivo = "savegame.sav"; dbOpenToWrite(hfile,sArquivo); if(dbFileOpen(hfile)) { dbPrint(" savegame() ok - Arquivo criado/aberto com sucesso!"); } else { MsgInfo(" Arquivo não foi aberto com sucesso!"); return; } // endif ------------------------------------------------------------------------------- nsts = dbFileOpen(hfile); int dbFileOpen ( int f ); Esta função retorna 1 caso o arquivo especificado tenha sido aberto com sucesso. Veja o exemplo de uso na função acima dbOpenToWrite(). ------------------------------------------------------------------------------- dbWriteString(hfile, sTexto); void dbWriteString ( int f, char* pString ); Esta função grava uma string no arquivo aberto. // Define ou coleta os dados char *sNome = "Jogador01"; int hfile = 6; // (...) abre o arquivo e verifica se está ok // Grava os dados dbWriteString (hfile, sNome); ------------------------------------------------------------------------------- dbWriteLong(hfile, nval) void dbWriteLong ( int f, int iValue ); Esta função escreve um valor do tipo long (4 bytes) no arquivo. // Define ou coleta os dados long nPontos = 558000; int hfile = 6; // (...) abre o arquivo e verifica se está ok // Grava os dados dbWriteLong (hfile, nPontos); ------------------------------------------------------------------------------- dbWriteWord (hfile, nval) void dbWriteWord ( int f, int iValue ); Esta função um valor tipo word (2 bytes) no arquivo. // Define ou coleta os dados WORD nVidas = 16; int hfile = 6; // (...) abre o arquivo e verifica se está ok // Grava os dados dbWriteWord (hfile, nVidas); ------------------------------------------------------------------------------- dbWriteByte(hfile, nval) void dbWriteByte ( int f, int iValue ); Esta função escreve um byte no arquivo. // Define ou coleta os dados char *sNome = "Jogador01"; int nSaude = 68; int hfile = 6; // (...) abre o arquivo e verifica se está ok // Grava os dados dbWriteByte (hfile, nSaude); ------------------------------------------------------------------------------- dbCloseFile(hfile) void dbCloseFile ( int f ); Fecha o arquivo que foi aberto em modo leitura ou gravação Ex.: // Fechando o arquivo... dbCloseFile(hfile); ------------------------------------------------------------------------------- dbOpenToRead(hfile, sArquivo) void dbOpenToRead( int f, char* pFilename ); Abre um arquivo para leitura. Ex.: char *sArquivo = "savegame.sav"; // Abre e verifica arquivo int hfile = 2; dbOpenToRead(hfile,sArquivo); ------------------------------------------------------------------------------- dbReadLong(hfile, &nval) int dbReadLong( int f, int* pInteger ); Lê um (long) valor de 32 bits do arquivo. Ex.: // (...) abre o arquivo para leitura e verifica se está ok int np = 0; dbReadLong (hfile, &np); ------------------------------------------------------------------------------- dbReadWord (hfile, &nval) WORD dbReadWord ( int f, WORD* pWord ); Lê um (word) valor de 16 bits do arquivo. Ex.: // (...) abre o arquivo para leitura e verifica se está ok WORD nv = 0; dbReadWord (hfile, &nv); ------------------------------------------------------------------------------- dbSkipBytes(hfile, nbytes); void dbSkipBytes ( int f, int iSkipValue ); Esta função desloca o ponteiro de leitura para a frente pulando uma quantidade especifica de bytes. Você vai usar essa função geralmente para pular bytes de controle ou de demarcação de dados. Veja abaixo na função dbReadByte() um exemplo de uso. ------------------------------------------------------------------------------- dbReadByte(hfile, &nval) unsigned char dbReadByte ( int f, unsigned char* pByte ); Esta função lê um byte do arquivo. Você pode usar esta função para ler uma string que nada mais é do que uma sequência de bytes. Ex.: // Define ou coleta os dados char *sNome = "Jogador01"; int hfile = 6; // (...) abre o arquivo para gravação e verifica se está ok // Grava os dados dbWriteString (hfile, sNome); // (...) abre o arquivo para leitura e verifica se está ok // memória para guardar os dados que serão lidos. unsigned char sn[13]="\0"; // A quantidade a ser lida deve ser a quantidade que foi gravada int ntam = strlen("jogador01"); // Lê o byte e estoca-o em ns[posição] for (int ncx=0; ncx < ntam; ncx++) dbReadByte(hfile, &sn[ncx]); dbSkipBytes(hfile,2); Repare no exemplo acima que usamos a função dbSkypeBytes() para pular 2 bytes para frente e assim posicionar corretamente o ponteiro no próximo dado a ser lido do arquivo. Esses dois bytes que foram pulados são os caractereres 0x0D 0x0A que são usados para ocasionar um avanço de linha em funções ou aplicativos que exibem texto. Outro pequeno exemplo: BYTE ns = 0; dbReadByte (hfile, &ns); ------------------------------------------------------------------------------- Veja o programa exemplo dessa sessão:
// savegame.cpp // Este programa ilustra como salvar e carregar(load) status de jogo(savegame) #include "DarkGDK.h" // Protótipo das funções void initsys(); // inicializa o sistema void MsgInfo(char *cText); // Mostra uma mensagem na tela void savegame(void); // Salva jogo void loadgame(void); // Carrega jogo // Flag para terminar o programa. 1 = terminar int terminar = 0; // Elenco de cores #define nBranco 0xFFFFFF // ---------------------------------------------------------------------------- void DarkGDK ( void ) { // Começo da aplicação DarkGdk initsys(); savegame(); loadgame(); // Looping principal while ( LoopGDK ( ) ) { if (dbMouseClick() == 2) terminar = 1; if (terminar == 1) break; dbSync ( ); } // fim do while return; } // endfunction DarkGDK() // ---------------------------------------------------------------------------- void initsys() { // Esta função inicializa o sistema dbSyncOn( ); dbCLS ( nBranco); dbInk( 0, nBranco ); dbSetWindowTitle("savegame.cpp"); dbSetTextOpaque(); } // initsys().fim // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- void MsgInfo(char *cText) { MessageBox(0, cText, "savegame.cpp", MB_OK); }// endfuncion MsgInfo void savegame(void) { char *sArquivo = "savegame.sav"; char sinfo[255]; if (dbFileExist(sArquivo) == 1) dbDeleteFile(sArquivo); char *sNome = "Jogador01"; // Jogador01 WORD nVidas = 0x4242; // 16.962 - codificado em ascii: BB long nPontos = 0x43434343; // 1.128.481.603 - codificado em ascii: CCCC int nSaude = 0x44 ; // 68 - codificado em ascii: D // Abre o arquivo e verifica que está ok int hfile = 6; dbOpenToWrite(hfile,sArquivo); if(dbFileOpen(hfile)) { dbPrint("savegame() ok - Arquivo criado/aberto com sucesso!"); } else { MsgInfo("Arquivo não foi aberto com sucesso!"); return; } // endif // Grava os dados dbWriteString (hfile, sNome); dbWriteWord (hfile, nVidas); dbWriteLong (hfile, nPontos); dbWriteByte (hfile, nSaude); // Mostra os dados gravados dbPrint(" "); dbPrint("Dados gravados: "); sprintf(sinfo, "Nome:%s Vidas:%d Saude:%d Pontos:%li", sNome, nVidas, nSaude, nPontos); dbPrint(sinfo); // Fechando o arquivo dbCloseFile(hfile); dbPrint(" "); } // endfunction: savegame() void loadgame() { char *sArquivo = "savegame.sav"; char sinfo[255]; if (dbFileExist(sArquivo) != 1) { MsgInfo("Arquivo savegame.sav não existe"); return; } WORD nv = 0; int np = 0; unsigned char sn[13]="\0"; BYTE ns = 0; // Mostra variáveis antes da leitura dbPrint(" "); dbPrint("----------------------- loadgame() ok --------------------------"); sprintf(sinfo, "Nome: %s Vidas: %d Saude: %d Pontos: %li", sn, nv, ns, np, ns); dbPrint("Valores das variaveis antes da leitura:"); dbPrint(sinfo); // Abre e verifica arquivo int hfile = 2; dbOpenToRead(hfile,sArquivo); if(dbFileOpen(hfile)) { dbPrint(" "); dbPrint("loadgame() ok - Arquivo aberto com sucesso para leitura!"); } else { MsgInfo("Arquivo não foi aberto com sucesso!"); return; } int ntam = strlen("jogador01"); for (int ncx=0; ncx < ntam; ncx++) dbReadByte(hfile, &sn[ncx]); dbSkipBytes(hfile,2); //Esta função não está funcionado: ReadString() dbReadWord ( hfile, &nv); dbReadLong (hfile, &np); dbReadByte (hfile, &ns); dbPrint(" "); dbPrint("Variaveis depois da leitura: "); sprintf(sinfo, "Nome: %s Vidas: %d Saude: %d Pontos: %li", sn, nv, ns, np, ns); dbPrint(sinfo); // Fechando o arquivo... dbCloseFile(hfile); } // endfunction: loadgame

1.3 Salvando e recuperando floats dbWriteFloat(hfile, nval) void dbWriteFloat ( int f, float fValue ); Esta função escreve um valor do tipo float no arquivo. // Define ou coleta os dados float x = 320.10f; float y = 240.11f; float z = 100.12f; // (...) abre o arquivo e verifica se está ok // Grava os dados dbWriteFloat (hfile, x); dbWriteFloat (hfile, y); dbWriteFloat (hfile, z); ------------------------------------------------------------------------------- dbReadFloat(hfile, &nval) void dbReadFloat ( int f, float *pFloat ); Esta função lê um valor do tipo float do arquivo. // Reserva espaço de memória float u, v, w; u = v = w = 0.0f; // (...) abre o arquivo e verifica se está ok // Lê os dados dbReadFloat (hfile, &u); dbWriteFloat (hfile, &v); dbWriteRead (hfile, &w); ------------------------------------------------------------------------------- Veja o programa exemplo abaixo:
// myfloats.cpp // Este programa ilustra como salvar e carregar(load) status de jogo(savegame) #include "DarkGDK.h" // Protótipo das funções void initsys(); // inicializa o sistema void MsgInfo(char *cText); // Mostra uma mensagem na tela void savegame(void); // Salva jogo void loadgame(void); // Carrega jogo // Flag para terminar o programa. 1 = terminar int terminar = 0; // ---------------------------------------------------------------------------- void DarkGDK ( void ) { // Começo da aplicação DarkGdk initsys(); savegame(); loadgame(); // Looping principal while ( LoopGDK ( ) ) { if (dbMouseClick() == 2) terminar = 1; if (terminar == 1) break; dbSync ( ); } // fim do while return; } // endfunction DarkGDK() // ---------------------------------------------------------------------------- void initsys() { // Esta função inicializa o sistema dbSyncOn( ); dbCLS ( 0xFFFFFF); dbInk( 0x0000FF, 0xFFFFFF ); dbSetWindowTitle("myfloats.cpp"); dbSetTextOpaque(); } // initsys().fim // ---------------------------------------------------------------------------- void MsgInfo(char *cText) { MessageBox(0, cText, "myfloats.cpp", MB_OK); }// endfuncion MsgInfo // ---------------------------------------------------------------------------- void savegame(void) { char *sArquivo = "myfloats.sav"; char sinfo[255]; if (dbFileExist(sArquivo) == 1) dbDeleteFile(sArquivo); float x = 320.10f; float y = 240.11f; float z = 100.12f; // Abre o arquivo e verifica que está ok dbPrint(" "); int hfile = 6; dbOpenToWrite(hfile,sArquivo); if(dbFileOpen(hfile)) { dbPrint(" savegame() ok - Arquivo criado/aberto com sucesso!"); } else { MsgInfo(" Arquivo não foi aberto com sucesso!"); return; } // endif // Grava os dados dbWriteFloat (hfile, x); dbWriteFloat (hfile, y); dbWriteFloat (hfile, z); // Mostra os dados gravados dbPrint(" "); dbPrint(" Dados gravados: "); sprintf(sinfo, " Posicao do jogador: (%f, %f, %f)",x,y,z); dbPrint(sinfo); // Fechando o arquivo dbCloseFile(hfile); dbPrint(" "); } // endfunction: savegame() // ---------------------------------------------------------------------------- void loadgame() { char *sArquivo = "myfloats.sav"; char sinfo[255]; if (dbFileExist(sArquivo) != 1) { MsgInfo(" Arquivo myfloats.sav não existe"); return; } float u, v, w; u = v = w = 0.0f; // Mostra variáveis antes da leitura dbPrint(" "); dbPrint(" ----------------------- loadgame() ok --------------------------"); sprintf(sinfo, " Posicao do jogador: (%f, %f, %f)",u,v,w); dbPrint(" Valores das variaveis antes da leitura:"); dbPrint(sinfo); // Abre e verifica arquivo int hfile = 2; dbOpenToRead(hfile,sArquivo); if(dbFileOpen(hfile)) { dbPrint(" "); dbPrint(" loadgame() ok - Arquivo aberto com sucesso para leitura!"); } else { MsgInfo(" Arquivo não foi aberto com sucesso!"); return; } dbReadFloat ( hfile, &u); dbReadFloat ( hfile, &v); dbReadFloat ( hfile, &w); dbPrint(" "); dbPrint(" Variaveis depois da leitura: "); sprintf(sinfo, " Posicao do jogador: (%f, %f, %f)",u,v,w); dbPrint(sinfo); // Fechando o arquivo... dbCloseFile(hfile); } // endfunction: loadgame

index << >>


Produzido por Gameprog: Jair Pereira - Setembro/2013 © gameprog.br@gmail.com http://www.gameprog.com.br http://www.nucleoararat.com.br