Kończę programowanie na kurs programowania gier wideo i chcę wiedzieć, jak utworzyć plik zapisu dla mojej gry, aby użytkownik mógł grać, a następnie wrócić później. Każdy pomysł, jak to się robi, wszystko, co zrobiłem wcześniej, to programy uruchamiane pojedynczo.
c++
savegame
serialization
Tucker Morgan
źródło
źródło
Odpowiedzi:
Aby zapisać zmienne w pamięci na dysku twardym, należy użyć serializacji . Istnieje wiele rodzajów serializacji, w .NET XML jest powszechnym formatem, chociaż dostępne są serializatory binarne i JSON. Nie jestem zbytnio programistą C ++, ale szybkie wyszukiwanie ujawniło przykład serializacji w C ++:
Istnieją biblioteki, które oferują funkcje serializacji. Niektóre są wymienione w innych odpowiedziach.
Zmienne, które Cię zainteresują, prawdopodobnie będą związane ze stanem gry. Na przykład prawdopodobnie będziesz chciał znać tego rodzaju informacje
Naprawdę nie obchodzi cię, jakie tekstury są używane (chyba że twój gracz może zmienić ich wygląd, to szczególny przypadek), ponieważ zwykle są takie same. Musisz skupić się na zapisywaniu ważnych danych gry.
Gdy zaczynasz grę, zaczynasz normalnie grę „nową” (ładuje to tekstury, modele itp.), Ale w odpowiednim czasie ładujesz wartości z pliku zapisu z powrotem do obiektu stanu gry, zastępując „domyślną” nową stan gry. Następnie pozwalasz graczowi wznowić grę.
Znacznie uprościłem to tutaj, ale powinieneś poznać ogólny pomysł. Jeśli masz bardziej szczegółowe pytanie, zadaj tutaj nowe pytanie, a my możemy spróbować Ci pomóc.
źródło
Zazwyczaj jest to specyficzne dla twojej gry. Jestem pewien, że do tej pory nauczyłeś się pisać i odczytywać pliki z twoich zajęć. Podstawową ideą jest:
To, co napiszesz, zależy od ciebie. Jednym ze sposobów zapisu jest zapisanie zmiennych w określonej kolejności w postaci strumienia bajtów. Następnie podczas ładowania wczytaj je do swojego programu w tej samej kolejności.
Na przykład (szybkim pseudo kodem):
źródło
Prawdopodobnie istnieje wiele sposobów, aby to zrobić, ale najprostszym, który zawsze znajdowałem i którego używałem zarówno osobiście, jak i zawodowo, jest stworzenie struktury zawierającej wszystkie wartości, które chcę zapisać.
Następnie po prostu zapisuję / fread dane do i z pliku przy użyciu podstawowych wartości we / wy pliku. InventoryCount to liczba struktur elementów zapisanych po głównej strukturze SaveGameData w pliku, więc wiem, ile z nich należy odczytać po pobraniu tych danych. Kluczem tutaj jest to, że gdy chcę zapisać coś nowego, chyba że jest to lista przedmiotów lub tym podobne, wszystko, co muszę zrobić, to dodać wartość do struktury gdzieś. Jeśli jest to lista elementów, będę musiał dodać przepustkę odczytu, jak już sugerowałem dla obiektów Item, licznik w nagłówku głównym, a następnie wpisy.
Ma to wadę polegającą na tym, że różne wersje pliku składowania są ze sobą niezgodne bez specjalnej obsługi (nawet jeśli są to tylko domyślne wartości dla każdego wpisu w głównej strukturze). Ale ogólnie sprawia to, że system można łatwo rozszerzyć, dodając nową wartość danych i wprowadzając wartość w razie potrzeby.
Ponownie, istnieje kilka sposobów, aby to zrobić, a to może prowadzić bardziej do C niż C ++, ale wykonało to zadanie!
źródło
Najpierw musisz zdecydować, jakie dane należy zapisać. Na przykład może to być lokalizacja postaci, jej wynik i liczba monet. Oczywiście twoja gra będzie prawdopodobnie znacznie bardziej złożona, dlatego musisz zapisać dodatkowe dane, takie jak numer poziomu i lista wrogów.
Następnie napisz kod, aby zapisać to w pliku (użyj ofstream). Stosunkowo prosty format, którego można użyć, jest następujący:
Tak więc plik wyglądałby następująco:
Co oznaczałoby, że był na pozycji (14, 96) z wynikiem 4200 i 100 monet.
Musisz także napisać kod, aby załadować ten plik (użyj ifstream).
Ratowanie wrogów można wykonać, włączając ich pozycję do pliku. Możemy użyć tego formatu:
Najpierw
number_of_enemies
jest czytany, a następnie każda pozycja jest czytana za pomocą prostej pętli.źródło
Jedno dodanie / sugestia dodałoby poziom szyfrowania do serializacji, aby użytkownicy nie mogli edytować swoich wartości tekstowych na „9999999999999999999”. Jednym z dobrych powodów jest zapobieganie przepełnieniu liczb całkowitych (na przykład).
źródło
Myślę, że najlepszym rozwiązaniem jest zwiększenie :: serializacja, ponieważ łatwo jest propagować w hierarchii. Wystarczy wywołać funkcję zapisu / ładowania najwyższego obiektu, a wszystkie klasy można łatwo utworzyć.
Zobacz: http://www.boost.org/doc/libs/1_49_0/libs/serialization/doc/index.html
źródło
Dla kompletności chcę wspomnieć o bibliotece serializacji c ++, z której osobiście korzystam i której jeszcze nie wymieniono: zbóż .
Jest łatwy w użyciu i ma ładną, czystą składnię do serializacji. Oferuje również wiele rodzajów formatów, w których można zapisać (XML, Json, Binary (w tym wersja przenośna z szacunkiem endianess)). Obsługuje dziedziczenie i jest tylko nagłówkiem,
źródło
Twoja gra naruszy struktury danych (mam nadzieję?), Które musisz przekształcić w bajty (serializować), aby móc je przechowywać. W przyszłości możesz załadować te bajty z powrotem i przekształcić je z powrotem w oryginalną strukturę (deserializacja). W C ++ nie jest to takie trudne, ponieważ refleksja jest bardzo ograniczona. Ale niektóre biblioteki mogą ci w tym pomóc. Napisałem o tym artykuł: https://rubentorresbonet.wordpress.com/2014/08/25/an-overview-of-data-serialization-techniques-in-c/ Zasadniczo proponuję, abyś spojrzał na biblioteka zbóż, jeśli możesz celować w kompilatory C ++ 11. Nie ma potrzeby tworzenia plików pośrednich, takich jak protobuf, więc zaoszczędzisz tam trochę czasu, jeśli chcesz uzyskać szybkie wyniki. Możesz także wybierać między wersją binarną i JSON, więc może to pomóc w debugowaniu tutaj.
Ponadto, jeśli bezpieczeństwo stanowi problem, możesz zaszyfrować / odszyfrować przechowywane dane, zwłaszcza jeśli używasz formatów czytelnych dla ludzi, takich jak JSON. Pomocne są tutaj algorytmy takie jak AES.
źródło
Musisz użyć
fstream
do plików wejściowych / wyjściowych. Składnia jest prosta EX:Lub
Możliwe są inne działania na pliku: append , binary , trunc itp. Użyłbyś tej samej składni jak powyżej, zamiast tego wstawiamy std :: ios: :( flagi), na przykład:
ios::out
dla operacji wyjściowejios::in
do operacji wprowadzaniaios::binary
do binarnej (surowego bajtu) operacji We / Wy, zamiast opartej na znakachios::app
aby zacząć pisać na końcu plikuios::trunc
jeśli plik już istnieje, zastąp starą treść i zastąp nowąios::ate
- ustaw wskaźnik pliku „na końcu” dla wejścia / wyjściaDawny:
Oto bardziej kompletny, ale prosty przykład.
źródło
goto
s zlinczujesz się w miejscu publicznym. Nie używajgoto
s.