howTo :: Pliki zapisu gry

Jak poradzić sobie ze stworzeniem zapisu gry tak, aby gra po wczytaniu wróciła do poprzedniego miejsca.

Na początku chciałbym Was przywitać w mojej nowej serii luźno powiązanych ze sobą poradników z cyklu „howTo”, gdzie moim głównym celem jest przekazanie Wam wskazówek jak coś jest zrobione, jak ta rzecz działa. Na blogu znajdziecie ogólne przedstawienie teorii, z kolei ewentualną implementację problemu przedstawię w materiale wideo na samym dole danego wpisu.

 

Czym jest zapis gry?


Spójrzmy na definicję, dzięki temu może spojrzymy na problem od nieco innej strony:

Zapis gry – obecnie jest to zazwyczaj plik zapisany w pamięci trwałej (najczęściej na dysku twardym, karcie pamięci, lub w chmurze), w którym znajdują się informacje o postępie poczynionym w grze komputerowej.

Źródło: Wikipedia

Do tej definicji moglibyśmy dodać, że w zapisach gier są zawarte informacje jedynie niezbędne do kontynuacji gry po jej ponownym wczytaniu.

 

Główny problem


Głównym problemem, czy też pytanie jakie pojawia się wśród młodych deweloperów: jakie dane powinienem zapisać?

Tutaj chciałbym cię uświadomić, że należy postępować zgodnie z zasadą: „Less is more”, co oznacza że im mniej danych zapiszemy w pliku tym lepiej.

Chciałbym Wam zwrócić uwagę, że nie ma ogólnej zasady co zapis gry musi posiadać, czego nie może bo sporo zależy od samej gry, którą piszemy. Musimy się zastanowić jakie informacje muszą zostać zapisane, tak aby gracz po powrocie do gry nie odczuł wewnętrznego dyskomfortu związanego z faktem, że gra przed wyjściem wyglądała zupełnie inaczej niż po jej wczytaniu, np. jeżeli piszemy shootera z ograniczoną ilością amunicji, to na pewno w zapisie gry musimy uwzględnić ile gracz posiada amunicji w chwili zapisu inaczej mogłoby dojść do sytuacji gdy gracz przed wyjściem nie miał wcale amunicji, a po wczytaniu ma jej pełny zapas.

Jak widzimy, pewne informacje musimy zapisać i kontynuując przykład shootera, nie możemy zbyt wielu informacji trzymać bo inaczej uzyskiwaliśmy koszmarnie ciężki plik zapisu. I tak gdy jesteśmy w trakcie walki gdzie na scenie jest jednocześnie 1000 pocisków, zapisanie tylko informacji o samych pociskach (przy minimum informacji: typ pocisku, wektor siły, pozycja) zajmie bardzo dużo miejsca, a to tylko pociski.

Nie wiem czy zauważyłeś, ale w grach tego typu zazwyczaj się nie pozwala tworzyć zapisu w trakcie walki, to jest jeden z powodów. Jeżeli, żaden NPC nie chce atakować gracza to do kompletności zapisu wystarczy jedynie pozycja wrogów na mapie i ich typ.

 

Zapis to iluzja


Zauważyliśmy już jedną sztuczkę jaką stosuje się przy zapisach gier: zapisujemy grę w sytuacjach łatwych do odtworzenia.

Teraz chciałbym pomóc pozbyć się iluzji, że po wczytaniu gry to co widzimy jest idealnym odzwierciedleniem tego co widzieliśmy przed zapisem i wyjściem z gry: zamrożonym  fragmentem gry czekającym na ponowne przyjście gracza.

Jak myślisz, czy po zapisie i wczytaniu gry w tym miejscu zobaczymy dokładnie te same postaci?

Wiedźmin 3

Nie. Część z nich zniknie, część pojawi się w innym miejscu, a zleceniodawca, który musi pojawić się w tym miejscu będzie na pewno w innej pozie, w innej klatce animacji. Na pewno nie będzie dokładnie taki sam jak przy zapisie.

Cała sztuczka polega na stworzeniu iluzji kontynuacji gry w dokładnie tym samym miejscu. Czuję się teraz nieco jak Morfeusz, który zapytał Neo:

Do you think that’s air you’re breathing now?

 

Przykładowy zapis gry


Jak wspomniałem wcześniej każdy zapis jest minimalnie inny, to jednak w pewnym sensie każdy jest do siebie podobny: (zazwyczaj) są robione w logiczny sposób i łatwy do odczytania (nawet w trybie tekstowym) sposób.

W przypadku Kerbal Space Program plik zapisu jest zrobiony z łatwo czytelnych sekcji:

Cały zapis gry składa się z sekcji, które mogą się składać z podsekcji, w których zapisywane są wartości. Ogólny zapis gry sprowadza się do schematu:

W ten sposób można w dość wygodny sposób przeszukiwać potrzebne informacje i je zmieniać bez konieczności przepisywania całego pliku, dość tego często stosuje się do tego XML, który również ma swoje kategorie, w których są zmienne, etc.

 

Podsumowując


Podsumowując mój wywód w kilku krótkich punktach zapisy powinny:

  1. Być możliwie jak najkrótsze, nie zawierające zbędnych informacji.
  2. Powinny umożliwiać odtworzenie danych na podstawie zapisanych informacji (jeżeli jakąś daną możesz obliczyć na podstawie danych, które już posiadasz to oznacza, że jej nie potrzebujesz w pliku zapisu).
  3. Być zapisane w „przyjazny” dla gry sposób, umożliwiający łatwe „przeskakiwanie” niektórych sekcji.

Mam nadzieję, że Wam pomogłem. Jeżeli macie jakieś uwagi odnośnie tego wpisu, pytania, albo po prostu chcecie podzielić się Waszym zdaniem, to zapraszam do komentowania tego wpisu.

Code ON!


  • filipekczek7

    O, bardzo fajny temat, jedna z ważniejszych rzeczy w grze 🙂 Prawdą jest to, że rzeczywiście nie trzeba zapisywać klatki animacji danych NPC-ów, które i tak się spawnują w losowych miejscach na określonym terenie. Nie trzeba zapisywać niepotrzebnych do rozgrywki rzeczy.
    Tylko szkoda, że nie wspomniałeś o serializacji, o plikach binarnych, ani w ogóle jak takie coś zapisywać. Znaczy się, wspomniałeś, jak ładnie zapisać (w sekcjach) i bez zbędnych informacji, ale jednak nie w kodzie, w większości teoria. Oczywiście, każdy język ma inny sposób, ale tutaj przecież programujemy w C++ 😉 No chyba, że co nieco o tym masz w kursie ,,Piszemy grę w SFML’u”, to zwracam honor 😉

    • Jak już wspomniałem: seria „howTo” we wpisach to przede wszystkim teoria, ewentualne implementacje prostych systemów to kod, tylko że ten temat jest ciężki do implementacji w sposób uniwersalny, jeżeli chce się jedynie pokazać jak takie coś może wyglądać. Jasne mógłbym napisać przy np użyciu XML’a klasę do zapisu/odczytu save’a, ale mam wrażenie że to co zrobiłbym na filmie odbiegało by dość mocno od tego co chciałem przekazać na blogu, czyli ideę tego jak powinien wyglądać dobrze skonstruowany zapis.