Збереження ігрового стану при виході на iPhone за допомогою Objective-C


Відповіді:


7

Ось метод, який я використовував у своїх іграх.

По-перше, кожен об'єкт, який потрібно зберегти, повинен реалізувати протокол кодування NSC. Ви хочете зберігати лише дані своєї моделі та нічого конкретного для поточного процесу. Це означає, що ви не можете зберігати покажчики або будь-які ідентифікатори ресурсів, які ОС дає вам під час виконання. Для покажчиків ви можете це легко виправити, просто переконавшись, що ви кодуєте об'єкти, на які вони вказують, замість самих покажчиків. Для інших ресурсів вам знадобиться спосіб підключення вашого об'єкта до нового ресурсу під час виконання.

По-друге, переконайтесь, що до всіх ваших ігрових об’єктів можна отримати доступ через один кореневий об’єкт. Наприклад, цей об'єкт може бути головним об'єктом для всього ігрового стану. Інша можливість полягає в тому, що ви можете зберігати їх в одному з колекційних класів 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

Це багато в чому залежатиме від того, як була закодована ваша гра. Ви відстежуєте кілька іварів чи щось більш суттєве?

Якщо це всього лише кілька іварів, я, мабуть, напишу їх у пліст на тлі та завантажую його при запуску.

Якщо є більше ivars, вам може бути краще з CoreData (та / або збереження їх значень, коли вони змінюються, а не намагатися помістити все у закрите вікно).


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

1

Тим самим способом ви зберігаєте його, коли користувач натискає гру збереження, не виходячи з неї.

Це питання про те, як зберегти ігровий стан? Або як зробити щось при виході з програми?

На останнє, відповідь: 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 або подібне), щоб перевірити, чи продовжується гра, щоб переконатися, що хтось не заблокував файл, щоб спробувати обдурити.


1

Я б сказав, що ні. Збережіть це, коли це має сенс для гри, а не тоді, коли додаток закривається. Наприклад, якщо це покрокова гра, тоді зберігайте в кінці кожного ходу. Якщо це гра на основі рівня, збережіть в кінці кожного рівня. Для цього є кілька причин:

  • Мобільне використання дуже непередбачуване. Так, ви отримуєте сповіщення від iPhone SDK, коли програма закривається, але це може бути посеред усього, і перехід є не просто "вихід", це також отримання дзвінка, отримання тексту тощо.
  • У вас дуже обмежений час та ресурси, щоб вимкнути гру при виході з програми. Більшість із цього, ймовірно, буде спожито лише з призупиненням вашої гри та очищенням пам'яті. Не потрібно додавати до цього навантаження, зберігаючи ігровий стан.
  • Більшість ігор мають природні паузи, які мають сенс для економії. Ви можете скористатися цими паузами для безперебійного зберігання ігрового стану, і користувач ніколи не помітить, що ви витрачаєте додаткові ресурси.
  • Зберігаючи поступово під час гри, кількість даних, які потрібно зберегти, буде меншим за кожне збереження.

1

Ось приклад того, як реалізувати протокол NSCoding для деяких прикладів класів "map" та "player":

http://deadpanic.com/howtosave

Потім ви можете зберегти об'єкти за допомогою методу NSKeyedArchiver Dennis.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.