Speichern des Spielstatus beim Beenden auf dem iPhone mit Objective-C

10

Wie würden Sie Ihren Spielstatus beim Beenden für ein in Objective-C geschriebenes iPhone-Spiel speichern?

Dennis Munsie
quelle

Antworten:

7

Hier ist die Methode, die ich in meinen Spielen verwendet habe.

Zunächst muss jedes Objekt, das beibehalten werden muss, das NSCoding-Protokoll implementieren. Sie möchten nur Ihre Modelldaten und nichts Spezielles für den aktuellen Prozess speichern. Dies bedeutet, dass Sie keine Zeiger oder Ressourcen-IDs beibehalten können, die Ihnen das Betriebssystem zur Laufzeit zur Verfügung stellt. Bei den Zeigern können Sie dies leicht beheben, indem Sie nur sicherstellen, dass Sie die Objekte codieren, auf die sie zeigen, anstatt die Zeiger selbst. Für andere Ressourcen benötigen Sie eine Möglichkeit, Ihr Objekt zur Laufzeit mit der neuen Ressource zu verbinden.

Stellen Sie zweitens sicher, dass auf alle Ihre Spielobjekte über ein einziges Root-Objekt zugegriffen werden kann. Dieses Objekt kann beispielsweise ein Master-Objekt für den gesamten Spielstatus sein. Eine andere Möglichkeit besteht darin, dass Sie sie in einer der Foundation-Auflistungsklassen (NSMutableArray, NSMutableSet, NSMutableDictionary) speichern können.

Wenn Sie benachrichtigt werden, dass Ihre Anwendung in den Hintergrund verschoben wird (applicationDidEnterBackground), müssen Sie NSKeyedArchiver verwenden, um den gesamten Status in einer Datei zu speichern. Diese Datei sollte sich im Dokumentenverzeichnis für Ihre Anwendung befinden. Hier ist ein bisschen Code, um zu zeigen, wie das gemacht wird:

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

Wenn Sie feststellen, dass Sie wieder in den Vordergrund zurückgekehrt sind, sollten Sie die Sicherungsdatei entfernen, um beim nächsten Start Ihrer Anwendung Verwirrung zu vermeiden.

Beim Start der Anwendung müssen Sie überprüfen, ob die Sicherungsdatei vorhanden ist. Wenn Sie eine haben, laden Sie sie wie folgt auf:

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

Abhängig von Ihrem Design müssen Sie möglicherweise den Spielstatus durchlaufen und alle Ressourcen erneut verbinden, die Sie nicht beibehalten konnten. Dies hängt wirklich davon ab, wie sauber Ihr Modellcode von Ihrem Rendering-Code getrennt ist.

An diesem Punkt möchten Sie Ihr Spiel möglicherweise in einen angehaltenen Zustand versetzen, je nachdem, welche Art von Spiel Sie machen.

Hoffentlich hilft dies jemand anderem, der versucht, das Speichern von Spielen auf dem iPhone zu implementieren.

Dennis Munsie
quelle
2

Das Speichern des Spielstatus ist eine komplexe Frage, die stark davon abhängt, wie Sie Ihr Spiel selbst einrichten.

Speziell auf dem iPhone müssten Sie sich nur -(void)applicationWillTerminate:in Ihre einbinden UIApplicationDelegate, um zu erkennen, wann die Anwendung beendet wird, von Benutzeraktionen oder auf andere Weise. Sie haben jedoch nur wenig Zeit, um Ihre Arbeit zu erledigen, bevor das Betriebssystem Ihren Prozess beendet.

Tetrad
quelle
2
applicationWillTerminate funktioniert nur für Anwendungen, die Multitasking nicht unterstützen, oder für das SDK vor 4.0. Es ist besser, applicationDidEnterBackground mit Post-4.0-Code zu verwenden.
Dennis Munsie
1

Das hängt weitgehend davon ab, wie Ihr Spiel codiert wurde. Behalten Sie ein paar Ivar oder etwas Wesentlicheres im Auge?

Wenn es nur ein paar Ivar sind, würde ich sie wahrscheinlich auf eine Liste im Hintergrund schreiben und diese beim Start laden.

Wenn es mehr Ivars gibt, sind Sie mit CoreData möglicherweise besser dran (und / oder speichern ihre Werte, wenn sie sich ändern, anstatt zu versuchen, alles in das Schließfenster einzupassen).

BarrettJ
quelle
Mit der Zeit, die das Betriebssystem zum Herunterfahren zur Verfügung stellt, können Sie tatsächlich viel erreichen. Mit der Methode, die ich in meiner Antwort in dieser Zeit beschrieben hatte, konnte ich einige Spielobjekte (mindestens einige Hundert) beibehalten. Auch auf dem langsamen 1G iPod touch. Abhängig von der Art des Spiels, das Sie erstellen, funktioniert die CoreData-Lösung möglicherweise besser, wenn die App beendet wird, jedoch auf Kosten eines langsameren Spiels.
Dennis Munsie
1

Genauso wie Sie es speichern, wenn der Benutzer ein Speicherspiel stößt, ohne es zu beenden.

Ist diese Frage, wie man den Spielstatus speichert? Oder wie mache ich etwas beim App-Exit?

Für letzteres lautet die Antwort: appWillTerminate (oder appWillResignActive). In iOS4 oder höher können Sie zusätzliche Zeit anfordern (Google "iOS-4 zusätzliche Zeit anfordern"), wenn das Speichern Ihres Spiels eine Weile dauert.

Wenn Sie sich fragen, wie Sie den Spielstatus überhaupt speichern können, bin ich ein großer Fan von NSDictionary, um Werte zu speichern, die von der Game-Engine einfach weiter gelesen werden können, wenn Sie fortfahren.

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

Wenn Sie möchten, können Sie eine „Signatur“ (hinzufügen dh , wie md5 oder ähnliches) auf Spiel , um sicherzustellen , weiterhin sicherstellen , dass jemand mit der Datei nicht ausgemistet hat , um zu versuchen zu betrügen.

Olie
quelle
1

Ich würde sagen nicht. Speichern Sie es, wenn es für das Spiel sinnvoll ist, nicht, wenn die App beendet wird. Wenn dies beispielsweise ein rundenbasiertes Spiel ist, speichern Sie es am Ende jeder Runde. Wenn es sich um ein Level-basiertes Spiel handelt, speichern Sie es am Ende jedes Levels. Dafür gibt es mehrere Gründe:

  • Die mobile Nutzung ist sehr unvorhersehbar. Ja, Sie werden vom iPhone SDK benachrichtigt, wenn die App geschlossen wird, aber es kann sich um etwas handeln, und der Übergang wird nicht nur "beendet", sondern es wird auch ein Anruf empfangen, ein Text abgerufen usw.
  • Sie haben nur sehr wenig Zeit und Ressourcen, um Ihr Spiel beim Beenden der App herunterzufahren. Das meiste davon wird wahrscheinlich nur verbraucht, wenn Sie Ihr Spiel pausieren und den Speicher bereinigen. Es ist nicht erforderlich, diese Last durch Speichern des Spielstatus zu erhöhen.
  • Die meisten Spiele haben natürliche Pausen, die zum Speichern sinnvoll sind. Sie können diese Pausen nutzen, um den Spielstatus nahtlos zu speichern, und der Benutzer wird nie bemerken, dass Sie zusätzliche Ressourcen verbrauchen.
  • Durch schrittweises Speichern während des Spiels wird die zu speichernde Datenmenge pro Speicherung geringer.
Chris Garrett
quelle
1

Hier ist ein Beispiel für die Implementierung des NSCoding-Protokolls für einige Beispielklassen "map" und "player":

http://deadpanic.com/howtosave

Anschließend können Sie die Objekte mit der NSKeyedArchiver-Methode von Dennis speichern.

Smasher
quelle