Сохранение состояния игры при выходе на iPhone с Objective-C

10

Как бы вы сохранили состояние игры на выходе для игры для iPhone, написанной на Objective-C?

Деннис Манси
источник

Ответы:

7

Вот метод, который я использовал в своих играх.

Во-первых, каждый объект, который необходимо сохранить, должен реализовывать протокол NSCoding. Вы хотите хранить только данные модели и ничего конкретного для текущего процесса. Это означает, что вы не можете сохранять указатели или любые идентификаторы ресурсов, которые ОС предоставляет вам во время выполнения. Для указателей это можно легко исправить, просто убедившись, что вы кодируете объекты, на которые они указывают, вместо самих указателей. Для других ресурсов вам потребуется способ подключения вашего объекта к новому ресурсу во время выполнения.

Во-вторых, убедитесь, что все ваши игровые объекты доступны через один корневой объект. Например, этот объект может быть главным объектом для всего игрового состояния. Другая возможность заключается в том, что вы можете хранить их в одном из классов коллекции Foundation (NSMutableArray, NSMutableSet, NSMutableDictionary).

Когда вы получите уведомление о том, что ваше приложение переходит в фоновый режим (applicationDidEnterBackground), вам нужно будет использовать NSKeyedArchiver, чтобы сохранить все состояние в файл. Этот файл должен находиться в каталоге документов для вашего приложения. Вот немного кода, чтобы показать, как это делается:

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

Когда вы обнаружите, что вернулись на передний план, вы должны удалить файл сохранения, чтобы избежать путаницы при следующем запуске приложения.

При запуске приложения вам необходимо проверить наличие файла сохранения. Если у вас есть, вы загружаете его так:

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

В зависимости от вашего дизайна, вам может потребоваться пройти через состояние игры и повторно подключить любые ресурсы, которые вы не могли сохранить. Это действительно зависит от того, насколько четко отделен код вашей модели от кода рендеринга.

На этом этапе вы можете перевести свою игру в состояние паузы, в зависимости от того, какую игру вы делаете.

Надеюсь, это поможет кому-то еще, кто пытается реализовать сохранение игр на iPhone.

Деннис Манси
источник
2

Как сохранить состояние игры - сложный вопрос, который сильно зависит от того, как вы настроили свою игру.

На iPhone конкретно, вы просто должны вклиниться -(void)applicationWillTerminate:в вашем UIApplicationDelegateпоймать , когда приложение будет выходить из действий пользователя или иным образом . У вас есть немного времени, чтобы выполнить свою работу, прежде чем ОС убьет ваш процесс.

тетрада
источник
2
applicationWillTerminate работает только для приложений, которые не поддерживают многозадачность, или для SDK до 4.0. Лучше использовать applicationDidEnterBackground с кодом после 4.0.
Деннис Манси
1

Это будет во многом зависеть от того, как ваша игра была закодирована. Вы отслеживаете несколько иваров или что-то более существенное?

Если это всего лишь несколько иваров, я, вероятно, записал бы их в список на фоне и загрузил бы их при запуске.

Если иваров больше, вам лучше использовать CoreData (и / или сохранять их значения по мере их изменения, а не пытаться вписать все в закрывающееся окно).

BarrettJ
источник
На самом деле вы можете многое сделать за время, которое ОС дает вам для завершения работы. Мне удалось сохранить довольно много игровых объектов (по крайней мере, несколько сотен), используя метод, который я описал в своем ответе в то время. Даже на медленном 1G iPod touch. В зависимости от типа игры, которую вы делаете, решение CoreData может работать лучше при выходе из приложения, но за счет более медленного игрового процесса.
Деннис Манси
1

Точно так же, как вы сохраняете его, когда пользователь поднимает игру, не выходя из нее.

Это вопрос о том, как сохранить состояние игры? Или как сделать что-то на app-exit?

В последнем случае ответ будет следующим: appWillTerminate (или appWillResignActive.) В iOS4 или более поздней версии вы можете запросить дополнительное время (Google «iOS-4 запросить дополнительное время»), если ваша игра-сохранение занимает некоторое время.

Если вы спрашиваете, как вообще сохранить игровое состояние, я большой поклонник NSDictionary для хранения значений, которые легко читаются игровым движком при продолжении.

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

Если вы хотите, вы можете добавить «подпись» ( то есть , например, md5 или аналогичную) для проверки в игре, чтобы убедиться, что кто-то не взломал файл, чтобы попытаться обмануть.

Olie
источник
1

Я бы сказал, нет. Сохраняйте его, когда это имеет смысл для игры, а не когда приложение закрывается. Например, если это пошаговая игра, сохраняйте ее в конце каждого хода. Если это игра, основанная на уровнях, сохраняйте в конце каждого уровня. Есть несколько причин для этого:

  • Мобильное использование очень непредсказуемо. Да, iPhone SDK уведомляет вас о закрытии приложения, но оно может быть в середине всего, и переход не просто «завершается», он также принимает вызов, получает текст и т. Д.
  • У вас очень ограниченное время и ресурсы, чтобы закрыть игру при выходе из приложения. Большая часть этого, вероятно, будет потрачена на паузу в вашей игре и очистку памяти. Нет необходимости добавлять к этой загрузке, сохраняя состояние игры.
  • Большинство игр имеют естественные паузы, которые имеют смысл для сохранения. Вы можете воспользоваться этими паузами для плавного сохранения состояния игры, и пользователь никогда не заметит, что вы потребляете дополнительные ресурсы.
  • При постепенном сохранении во время игры количество сохраняемых данных будет меньше при сохранении.
Крис Гарретт
источник
1

Вот пример того, как реализовать протокол NSCoding для некоторых примеров классов «map» и «player»:

http://deadpanic.com/howtosave

Затем вы можете сохранить объекты, используя метод NSKeyedArchiver Дениса.

разгромная рецензия
источник