Stockage de l'état du jeu à la sortie sur l'iPhone avec Objective-C

10

Comment stockeriez-vous l'état de votre jeu à la sortie pour un jeu iPhone écrit en Objective-C?

Dennis Munsie
la source

Réponses:

7

Voici la méthode que j'ai utilisée dans mes jeux.

Tout d'abord, chaque objet qui doit être persistant doit implémenter le protocole NSCoding. Vous souhaitez uniquement stocker vos données de modèle et rien de spécifique au processus en cours. Cela signifie que vous ne pouvez pas conserver les pointeurs ou les identifiants de ressources que le système d'exploitation vous donne au moment de l'exécution. Pour les pointeurs, vous pouvez résoudre ce problème facilement en vous assurant simplement d'encoder les objets vers lesquels ils pointent au lieu des pointeurs eux-mêmes. Pour les autres ressources, vous aurez besoin d'un moyen de connecter votre objet à la nouvelle ressource lors de l'exécution.

Deuxièmement, assurez-vous que tous vos objets de jeu sont accessibles via un seul objet racine. Cet objet peut être un objet maître pour tout l'état du jeu, par exemple. Une autre possibilité est que vous puissiez les stocker dans l'une des classes de collection Foundation (NSMutableArray, NSMutableSet, NSMutableDictionary).

Lorsque vous êtes averti que votre application se déplace en arrière-plan (applicationDidEnterBackground), vous devrez utiliser NSKeyedArchiver pour enregistrer l'intégralité de l'état dans un fichier. Ce fichier doit se trouver dans le répertoire des documents de votre application. Voici un peu de code pour montrer comment cela se fait:

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

Lorsque vous détectez que vous êtes revenu au premier plan, vous devez supprimer le fichier de sauvegarde pour éviter toute confusion lors du prochain lancement de votre application.

Au démarrage de l'application, vous devez vérifier l'existence du fichier de sauvegarde. Si vous en avez un, vous le chargez comme ceci:

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

Selon votre conception, vous devrez peut-être parcourir l'état du jeu et reconnecter toutes les ressources que vous ne pourriez pas conserver. Cela dépend vraiment de la séparation nette de votre code de modèle avec votre code de rendu.

À ce stade, vous souhaiterez peut-être mettre votre jeu en pause, selon le type de jeu que vous créez.

Espérons que cela aide quelqu'un d'autre qui essaie d'implémenter la sauvegarde de jeu sur l'iPhone.

Dennis Munsie
la source
2

Comment stocker l'état du jeu est une question complexe qui dépend fortement de la façon dont vous configurez votre jeu lui-même.

Sur l'iPhone en particulier, il vous suffira de vous connecter -(void)applicationWillTerminate:à votre UIApplicationDelegatepour attraper le moment où l'application se fermera, de l'action de l'utilisateur ou autrement. Cependant, vous avez peu de temps pour faire votre travail avant que le système d'exploitation ne tue votre processus.

Tetrad
la source
2
applicationWillTerminate ne fonctionne que pour les applications qui ne prennent pas en charge le multitâche ou pour le SDK antérieur à 4.0. Il est préférable d'utiliser applicationDidEnterBackground avec du code post-4.0.
Dennis Munsie
1

Cela dépendrait en grande partie de la façon dont votre jeu a été codé. Gardez-vous une trace de quelques ivars ou quelque chose de plus substantiel?

S'il ne s'agit que de quelques ivars, je les écrirais probablement sur un plist en arrière-plan et les chargerais au démarrage.

S'il y a plus d'ivars, vous pourriez être mieux avec CoreData (et / ou enregistrer leurs valeurs au fur et à mesure qu'elles changent au lieu d'essayer de tout rentrer dans la fenêtre de fermeture).

BarrettJ
la source
Vous pouvez réellement faire beaucoup de choses avec le temps que le système d'exploitation vous donne pour arrêter. J'ai pu persister quelques objets de jeu (quelques centaines au moins) en utilisant la méthode que j'ai décrite dans ma réponse à l'époque. Même sur l'iPod touch 1G lent. Selon le type de jeu que vous créez, la solution CoreData peut fonctionner mieux lorsque l'application se ferme, mais au détriment d'un jeu plus lent.
Dennis Munsie
1

De la même manière que vous l'enregistrez lorsque l'utilisateur saute une sauvegarde sans quitter.

Cette question concerne-t-elle la sauvegarde de l'état du jeu? Ou comment faire quelque chose à la sortie de l'application?

Pour ce dernier, la réponse est: appWillTerminate (ou appWillResignActive.) Dans iOS4 ou version ultérieure, vous pouvez demander du temps supplémentaire (Google "iOS-4 request extra time") si votre sauvegarde prend du temps.

Si vous demandez comment enregistrer l'état du jeu, je suis un grand fan de NSDictionary pour stocker les valeurs facilement relues par le moteur de jeu.

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

Si vous le souhaitez, vous pouvez ajouter une "signature" ( c'est-à - dire , comme md5 ou similaire) pour vérifier sur le jeu continuer à vous assurer que quelqu'un n'a pas foutu le fichier pour essayer de tricher.

Olie
la source
1

Je dirais que non. Enregistrez-le lorsque cela a du sens pour le jeu, pas lorsque l'application se ferme. Par exemple, s'il s'agit d'un jeu au tour par tour, enregistrez à la fin de chaque tour. S'il s'agit d'un jeu basé sur le niveau, enregistrez à la fin de chaque niveau. Il y a plusieurs raisons à cela:

  • L'utilisation mobile est très imprévisible. Oui, vous êtes averti par le SDK de l'iPhone lorsque l'application se ferme, mais cela pourrait être au milieu de n'importe quoi, et la transition ne consiste pas seulement à "sortir", elle reçoit également un appel, reçoit un texte, etc.
  • Vous avez très peu de temps et de ressources pour arrêter votre jeu à la sortie de l'application. La majeure partie de cela sera probablement consommée juste avec la pause de votre jeu et le nettoyage de la mémoire. Pas besoin d'ajouter à cette charge en sauvegardant l'état du jeu.
  • La plupart des jeux ont des pauses naturelles qui ont du sens pour la sauvegarde. Vous pouvez profiter de ces pauses pour stocker en toute transparence l'état du jeu et l'utilisateur ne remarquera jamais que vous consommez des ressources supplémentaires.
  • En enregistrant de façon incrémentielle pendant le jeu, la quantité de données à enregistrer sera plus petite par sauvegarde.
Chris Garrett
la source
1

Voici un exemple de la façon d'implémenter le protocole NSCoding pour certains exemples de classes "map" et "player":

http://deadpanic.com/howtosave

Ensuite, vous pouvez enregistrer les objets à l'aide de la méthode NSKeyedArchiver de Dennis.

smasher
la source