Armazenando o estado do jogo na saída do iPhone com o Objective-C

10

Como você armazenaria o estado do seu jogo na saída de um jogo para iPhone escrito em Objective-C?

Dennis Munsie
fonte

Respostas:

7

Aqui está o método que eu usei nos meus jogos.

Primeiro, todo objeto que precisa ser persistido deve implementar o protocolo NSCoding. Você deseja armazenar apenas os dados do modelo e nada específico para o processo atual. Isso significa que você não pode persistir ponteiros ou identificações de recursos que o sistema operacional fornece a você em tempo de execução. Para os ponteiros, você pode corrigir isso facilmente, apenas codificando os objetos para os quais eles apontam, em vez dos ponteiros. Para outros recursos, você precisará de uma maneira de conectar seu objeto ao novo recurso em tempo de execução.

Segundo, verifique se todos os objetos do seu jogo podem ser acessados ​​através de um único objeto raiz. Este objeto pode ser um objeto mestre para todo o estado do jogo, por exemplo. Outra possibilidade é que você possa armazená-los em uma das classes da coleção Foundation (NSMutableArray, NSMutableSet, NSMutableDictionary).

Quando você for notificado de que seu aplicativo está entrando em segundo plano (applicationDidEnterBackground), será necessário usar o NSKeyedArchiver para salvar todo o estado em um arquivo. Esse arquivo deve estar no diretório de documentos do seu aplicativo. Aqui está um pouco de código para mostrar como isso é feito:

NSArray *docDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [docDirectories objectAtIndex:0];
NSString *saveFile = [docsPath stringByAppendingPathComponent:SAVE_STATE_FILENAME];
[NSKeyedArchiver archiveRootObject:gameState toFile:saveFile;

Quando você detectar que voltou ao primeiro plano, remova o arquivo de salvamento para evitar qualquer confusão na próxima vez em que o aplicativo for iniciado.

Na inicialização do aplicativo, você precisa verificar a existência do arquivo salvo. Se você tiver um, carregue-o assim:

NSArray *docDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [docDirectories objectAtIndex:0];
NSString *saveFile = [docsPath stringByAppendingPathComponent:SAVE_STATE_FILENAME];
[gameState release];
gameState = [[NSKeyedArchiver unarchiveObjectWithFile:saveFile] retain];

Dependendo do seu design, você pode precisar percorrer o estado do jogo e reconectar quaisquer recursos que não pudessem persistir. Isso realmente depende de como o código do modelo está separado do seu código de renderização.

Nesse ponto, você pode colocar seu jogo em um estado de pausa, dependendo do tipo de jogo que você está criando.

Espero que isso ajude alguém por aí que está tentando implementar a economia de jogos no iPhone.

Dennis Munsie
fonte
2

Como armazenar o estado do jogo é uma pergunta complexa e fortemente dependente de como você configura seu próprio jogo.

Especificamente no iPhone, você precisaria se conectar ao -(void)applicationWillTerminate:seu UIApplicationDelegatepara capturar quando o aplicativo sairá, da ação do usuário ou de outra forma. Você tem um curto período de tempo para fazer seu trabalho antes que o sistema operacional acabe com seu processo.

Tetrad
fonte
2
applicationWillTerminate funciona apenas para aplicativos que não suportam multitarefa ou para o SDK anterior à 4.0. É melhor usar applicationDidEnterBackground com código pós-4.0.
Dennis Munsie
1

Isso dependeria muito de como o seu jogo foi codificado. Você está acompanhando alguns ivars ou algo mais substancial?

Se forem apenas alguns ivars, eu provavelmente os escreveria em um plano de fundo e o carregaria na inicialização.

Se houver mais ivars, você poderá se beneficiar melhor com o CoreData (e / ou salvar seus valores conforme eles mudam, em vez de tentar encaixar tudo na janela fechada).

BarrettJ
fonte
Você pode realmente fazer muito com o tempo que o sistema operacional permite que você desligue. Consegui persistir alguns objetos do jogo (pelo menos algumas centenas) usando o método que descrevi na minha resposta naquele tempo. Mesmo no lento iPod touch 1G. Dependendo do tipo de jogo que você está criando, a solução CoreData pode funcionar melhor quando o aplicativo é encerrado, mas à custa de um jogo mais lento.
Dennis Munsie
1

Da mesma maneira que você o salva quando o usuário bate em um jogo salvo sem sair.

Esta é uma pergunta sobre como salvar o estado do jogo? Ou como fazer algo na saída do aplicativo?

Para o último, a resposta é: appWillTerminate (ou appWillResignActive.) No iOS4 ou posterior, você pode solicitar um tempo extra (Google "iOS-4 solicita tempo extra") se o seu jogo salvo demorar um pouco.

Se você está perguntando como salvar o estado do jogo, sou um grande fã do NSDictionary para armazenar valores facilmente relidos pelo mecanismo do jogo em continuar.

NSMutableDictionary *saveDict = [NSMutableDictionary dictionary];
[saveDict setValue: [NSNumber numberWithInt: currentScore] forKey: @"currentScore"];
// etc...
[saveDict writeToFile: saveFilePath atomically: YES];

Se você quiser, você pode adicionar uma "assinatura" ( ou seja , como MD5 ou similar) para verificar em jogo continuar a ter certeza de que alguém não fez muck com o arquivo para tentar enganar.

Olie
fonte
1

Eu diria que não. Salve-o quando fizer sentido para o jogo, não quando o aplicativo estiver saindo. Por exemplo, se este for um jogo baseado em turnos, salve no final de cada turno. Se for um jogo baseado em níveis, salve no final de cada nível. Existem algumas razões para isso:

  • O uso móvel é muito imprevisível. Sim, você é notificado pelo iPhone SDK quando o aplicativo é fechado, mas pode estar no meio de qualquer coisa, e a transição não está apenas "saindo", mas também recebendo uma chamada, recebendo um texto etc.
  • Você tem tempo e recursos muito limitados para encerrar o jogo na saída do aplicativo. A maior parte disso provavelmente será consumida apenas com a pausa do jogo e a limpeza da memória. Não é necessário adicionar a essa carga salvando o estado do jogo.
  • A maioria dos jogos tem pausas naturais que fazem sentido para economizar. Você pode tirar proveito dessas pausas para armazenar perfeitamente o estado do jogo, e o usuário nunca notará que você está consumindo recursos extras.
  • Ao salvar de forma incremental durante o jogo, a quantidade de dados a serem salvos será menor por salvamento.
Chris Garrett
fonte
1

Aqui está um exemplo de como implementar o protocolo NSCoding para alguns exemplos de classes "map" e "player":

http://deadpanic.com/howtosave

Em seguida, você pode salvar os objetos usando o método NSKeyedArchiver de Dennis.

esmagar
fonte