Przechowywanie stanu gry przy wyjściu na iPhonie z Objective-C


Odpowiedzi:


7

Oto metoda, której użyłem w swoich grach.

Po pierwsze, każdy obiekt, który musi zostać utrwalony, musi implementować protokół NSCoding. Chcesz tylko przechowywać dane modelu i nic konkretnego dla bieżącego procesu. Oznacza to, że nie można zachować wskaźników ani żadnych identyfikatorów zasobów, które system operacyjny podaje w czasie wykonywania. W przypadku wskaźników możesz to łatwo naprawić, po prostu upewniając się, że kodujesz obiekty, na które wskazują, zamiast samych wskaźników. W przypadku innych zasobów potrzebny będzie sposób na podłączenie obiektu do nowego zasobu w czasie wykonywania.

Po drugie, upewnij się, że do wszystkich twoich obiektów gry można uzyskać dostęp za pośrednictwem jednego obiektu głównego. Ten obiekt może być na przykład obiektem głównym dla całego stanu gry. Inną możliwością jest przechowywanie ich w jednej z klas kolekcji Foundation (NSMutableArray, NSMutableSet, NSMutableDictionary).

Po wyświetleniu powiadomienia o przeniesieniu aplikacji w tło (applicationDidEnterBackground) konieczne będzie użycie NSKeyedArchiver w celu zapisania całego stanu w pliku. Ten plik powinien znajdować się w katalogu dokumentów aplikacji. Oto trochę kodu pokazującego, jak to się robi:

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

Po wykryciu, że wróciłeś na pierwszy plan, usuń plik składowania, aby uniknąć nieporozumień przy następnym uruchomieniu aplikacji.

Podczas uruchamiania aplikacji należy sprawdzić, czy istnieje plik składowania. Jeśli masz, ładujesz go w następujący sposób:

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

W zależności od projektu może być konieczne przejście przez stan gry i ponowne połączenie wszystkich zasobów, których nie można było zachować. To naprawdę zależy od tego, jak czysto oddzielony jest Twój kod modelu od kodu renderującego.

W tym momencie możesz chcieć ustawić grę w stan pauzy, w zależności od rodzaju tworzonej gry.

Mam nadzieję, że pomoże to komuś innemu, kto próbuje wdrożyć zapisywanie gier na iPhonie.


2

Jak zapisać stan gry to złożone pytanie, które w dużej mierze zależy od konfiguracji samej gry.

Na iPhone specjalnie, by po prostu trzeba się podłączyć do -(void)applicationWillTerminate:w swojej UIApplicationDelegatezłapać, gdy aplikacja wyjdzie z działania użytkownika lub w inny sposób. Masz jednak niewiele czasu na wykonanie pracy, zanim system operacyjny zabije Twój proces.


2
applicationWillTerminate działa tylko w przypadku aplikacji, które nie obsługują wielozadaniowości lub zestawu SDK wcześniejszego niż 4.0. Lepiej jest użyć applicationDidEnterBackground z kodem post-4.0.
Dennis Munsie

1

Zależy to w dużej mierze od sposobu zakodowania gry. Czy śledzisz kilka ivarów czy coś bardziej znaczącego?

Jeśli to tylko kilka ivarów, prawdopodobnie zapisałbym je na liście w tle i załadowałbym przy starcie.

Jeśli jest więcej ivarów, lepiej może być z CoreData (i / lub zapisywać ich wartości, gdy się zmieniają, zamiast próbować dopasować wszystko do zamkniętego okna).


Rzeczywiście możesz wiele zrobić z czasem, jaki system operacyjny pozwala ci zamknąć. Byłem w stanie przetrwać całkiem sporo obiektów gry (przynajmniej kilkaset), używając metody opisanej w mojej odpowiedzi w tym czasie. Nawet w wolnym iPodzie touch 1G. W zależności od rodzaju tworzonej gry rozwiązanie CoreData może działać lepiej w przypadku zamykania aplikacji, ale kosztem wolniejszej rozgrywki.
Dennis Munsie

1

W ten sam sposób, w jaki zapisujesz, gdy użytkownik uderzy w grę zapisu bez wychodzenia.

Czy to pytanie o to, jak zapisać stan gry? Lub jak zrobić coś przy wyjściu z aplikacji?

W przypadku tego ostatniego odpowiedź brzmi: appWillTerminate (lub appWillResignActive.) W systemie iOS4 lub nowszym możesz poprosić o dodatkowy czas (Google „iOS-4 żąda dodatkowego czasu”), jeśli gra wymaga czasu.

Jeśli pytasz, jak w ogóle zapisać stan gry, jestem wielkim fanem NSDictionary do przechowywania wartości łatwo ponownie odczytanych przez silnik gry w dalszym ciągu.

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

Jeśli chcesz, możesz dodać „podpis” ( np. Md5 lub podobny), aby zweryfikować w grze, aby upewnić się, że ktoś nie zepsuł się z plikiem, aby spróbować oszukać.


1

Powiedziałbym nie. Zapisz go, gdy ma to sens dla gry, a nie kiedy aplikacja się kończy. Na przykład, jeśli jest to gra turowa, zapisz na końcu każdej tury. Jeśli jest to gra oparta na poziomie, zapisz na końcu każdego poziomu. Jest kilka powodów:

  • Korzystanie z telefonu komórkowego jest bardzo nieprzewidywalne. Tak, iPhone SDK otrzymuje powiadomienie, gdy aplikacja się zamyka, ale może to być coś w środku, a przejście nie polega tylko na „wychodzeniu”, ale również odbieraniu połączenia, otrzymywaniu wiadomości SMS itp.
  • Masz bardzo ograniczony czas i zasoby, aby zamknąć grę po wyjściu z aplikacji. Większość z nich zostanie prawdopodobnie zużyta po prostu po wstrzymaniu gry i oczyszczeniu pamięci. Nie trzeba dodawać do tego obciążenia, zapisując stan gry.
  • Większość gier ma naturalne przerwy, które mają sens dla oszczędzania. Możesz skorzystać z tych przerw, aby płynnie przechowywać stan gry, a użytkownik nigdy nie zauważy, że zużywasz dodatkowe zasoby.
  • Zapisując przyrostowo podczas gry, ilość danych do zapisania będzie mniejsza na zapis.

1

Oto przykład implementacji protokołu NSCoding dla niektórych przykładowych klas „map” i „player”:

http://deadpanic.com/howtosave

Następnie możesz zapisać obiekty za pomocą metody Dennis 'NSKeyedArchiver.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.