Almacenar el estado del juego en la salida del iPhone con Objective-C

10

¿Cómo almacenarías el estado de tu juego al salir para un juego de iPhone escrito en Objective-C?

Dennis Munsie
fuente

Respuestas:

7

Aquí está el método que utilicé en mis juegos.

Primero, cada objeto que necesita persistir debe implementar el protocolo NSCoding. Solo desea almacenar los datos de su modelo y nada específico del proceso actual. Esto significa que no puede persistir los punteros o los identificadores de recursos que el sistema operativo le proporciona en tiempo de ejecución. Para los punteros, puede solucionarlo fácilmente asegurándose de codificar los objetos a los que apuntan en lugar de los punteros. Para otros recursos, necesitará una forma de conectar su objeto al nuevo recurso en tiempo de ejecución.

En segundo lugar, asegúrese de que se pueda acceder a todos los objetos del juego a través de un único objeto raíz. Este objeto podría ser un objeto maestro para todo el estado del juego, por ejemplo. Otra posibilidad es que pueda almacenarlos en una de las clases de colección de Foundation (NSMutableArray, NSMutableSet, NSMutableDictionary).

Cuando reciba una notificación de que su aplicación se está moviendo hacia el fondo (applicationDidEnterBackground), deberá usar NSKeyedArchiver para guardar todo el estado en un archivo. Ese archivo debe estar en el directorio de documentos para su aplicación. Aquí hay un poco de código para mostrar cómo se hace eso:

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

Cuando detecte que ha vuelto al primer plano, debe eliminar el archivo guardado para evitar confusiones la próxima vez que inicie su aplicación.

Al iniciar la aplicación, debe verificar la existencia del archivo de guardar. Si tiene uno, lo carga así:

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];

Dependiendo de su diseño, es posible que deba recorrer el estado del juego y volver a conectar cualquier recurso que no pueda persistir. Esto realmente depende de cuán limpio esté el código de su modelo de su código de representación.

En este punto, es posible que desees poner tu juego en un estado de pausa, dependiendo del tipo de juego que estés haciendo.

Esperemos que esto ayude a alguien más que está tratando de implementar el juego guardado en el iPhone.

Dennis Munsie
fuente
2

Cómo almacenar el estado del juego es una pregunta compleja que depende en gran medida de cómo configuras el juego en sí.

En el iPhone en concreto, que sólo tendría que enganchar en -(void)applicationWillTerminate:en su UIApplicationDelegateatrapar cuando la aplicación se cerrará, a partir de la acción del usuario o de otra manera. Sin embargo, tiene poco tiempo para hacer su trabajo antes de que el sistema operativo mate su proceso.

Tétrada
fuente
2
applicationWillTerminate solo funciona para aplicaciones que no admiten multitarea o para el SDK anterior a 4.0. Es mejor usar applicationDidEnterBackground con código posterior a 4.0.
Dennis Munsie
1

Eso dependerá en gran medida de cómo se codificó su juego. ¿Está haciendo un seguimiento de algunos ivars o algo más sustancial?

Si solo se trata de unos pocos ivars, probablemente los escribiría en una lista de antecedentes y los cargaría al inicio.

Si hay más ivars, podría ser mejor con CoreData (y / o guardar sus valores a medida que cambian en lugar de tratar de encajar todo en la ventana cerrada).

BarrettJ
fuente
En realidad, puedes hacer mucho con el tiempo que el sistema operativo te da para cerrar. Pude persistir bastantes objetos del juego (al menos unos cientos) usando el método que describí en mi respuesta en ese momento. Incluso en el lento iPod touch de 1G. Dependiendo del tipo de juego que esté haciendo, la solución CoreData puede funcionar mejor cuando la aplicación se cierra, pero a expensas de un juego más lento.
Dennis Munsie
1

De la misma manera que lo guarda cuando el usuario topa un juego guardado sin salir.

¿Es esta pregunta acerca de cómo guardar el estado del juego? ¿O cómo hacer algo al salir de la aplicación?

Para este último, la respuesta es: appWillTerminate (o appWillResignActive). En iOS4 o posterior, puede solicitar tiempo extra (Google "iOS-4 solicita tiempo extra") si su partida guardada tarda un tiempo.

Si está preguntando cómo guardar el estado del juego, soy un gran admirador de NSDictionary para almacenar valores fácilmente releídos por el motor del juego al continuar.

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

Si lo desea, puede agregar una "firma" ( es decir , como md5 o similar) para verificar que en el juego continúe asegurándose de que alguien no haya alterado el archivo para intentar hacer trampa.

Olie
fuente
1

Yo diría que no. Guárdelo cuando tenga sentido para el juego, no cuando la aplicación se cierre. Por ejemplo, si este es un juego basado en turnos, guarde al final de cada turno. Si se trata de un juego basado en niveles, guarda al final de cada nivel. Hay un par de razones para esto:

  • El uso móvil es muy impredecible. Sí, el iPhone SDK te notifica cuando la aplicación se está cerrando, pero podría estar en medio de cualquier cosa, y la transición no es solo "salir", sino que también está recibiendo una llamada, un mensaje de texto, etc.
  • Tienes muy poco tiempo y recursos para cerrar tu juego al salir de la aplicación. La mayor parte de eso probablemente se consumirá solo con pausar el juego y limpiar la memoria. No es necesario agregar a esa carga guardando el estado del juego.
  • La mayoría de los juegos tienen pausas naturales que tienen sentido para guardar. Puede aprovechar estas pausas para almacenar sin problemas el estado del juego, y el usuario nunca notará que está consumiendo recursos adicionales.
  • Al guardar de forma incremental durante el juego, la cantidad de datos a guardar será menor por guardado.
Chris Garrett
fuente
1

Aquí hay un ejemplo de cómo implementar el protocolo NSCoding para algunos ejemplos de clases "map" y "player":

http://deadpanic.com/howtosave

Luego puede guardar los objetos utilizando el método NSKeyedArchiver de Dennis.

bombón
fuente