Jak zapisać stan gry?

27

Jaka jest procedura stosowana przez programistów gier w celu zapisywania i wznawiania stanu gry? jak pliki / mapowania. Chcę go zapisać na potrzeby gry typu tower defense i używam silnika gry unity3D.

Syed
źródło

Odpowiedzi:

16

Zasadniczo nie myślę o migawce pamięci, ale po prostu tworzę listę wartości, które należy zapisać między sesjami, i zapisuję te wartości w zewnętrznym pliku.

Zależy to oczywiście od potrzeb konkretnej gry, ale zwykle po prostu zapisuję stan bieżącego poziomu (tj. Gdzie są wszyscy wrogowie, jakie jest ich zdrowie itp.), A następnie rzeczy na wyższym poziomie, takie jak poziom gracza już się zakończył.

jhocking
źródło
3
+1 Tak to robię. Piszę to, czego potrzebuję, do pliku binarnego. A jeśli muszę dodać coś nowego, dodaję to na końcu, aby nie uszkodzić starych plików zapisywania.
chaosTechnician
To dobra wskazówka, aby nie łamać starych plików zapisywania, chociaż dodawanie danych na końcu nie ma znaczenia dla tego, jak zapisuję dane. Robię to poprzez serializację / deserializację Słownika, a kolejność w tej strukturze danych nie ma znaczenia.
jhocking
(w zasadzie kod w odpowiedzi
Jonasa
10

Ta odpowiedź jest specyficzna dla Unity3d .
W Unity większość klas można serializować, co oznacza, że ​​możesz przesyłać strumieniowo kompletne obiekty Unity na dysk. Poniższy kod UnityScript to sposób na serializację obiektu, zapisanie go na dysku i załadowanie go ponownie (po załadowaniu musisz rzutować obiekt):

import System;
import System.IO;
import System.IO.Stream;
import System.Runtime.Serialization;
import System.Runtime.Serialization.Formatters.Binary;

class SaveLoad {
        public static function SaveFile(filename:String, obj:Object):void {
                try {
                        Debug.Log("Writing Stream to Disk.", SaveLoad);
                        var fileStream:Stream = File.Open(filename, FileMode.Create);
                        var formatter:BinaryFormatter = new BinaryFormatter();
                        formatter.Serialize(fileStream, obj);
                        fileStream.Close();
                } catch(e:Exception) {
                        Debug.LogWarning("Save.SaveFile(): Failed to serialize object to a file " + filename + " (Reason: " + e.ToString() + ")");
                }
        }

        public static function LoadFile(filename:String):Object {
                try {
                        Debug.Log("Reading Stream from Disk.", SaveLoad);
                        var fileStream:Stream = File.Open(filename, FileMode.Open, FileAccess.Read);
                        var formatter:BinaryFormatter = new BinaryFormatter();
                        var obj:Object= formatter.Deserialize(fileStream);
                        fileStream.Close();
                        return obj;
                } catch(e:Exception) {
                        Debug.LogWarning("SaveLoad.LoadFile(): Failed to deserialize a file " + filename + " (Reason: " + e.ToString() + ")");
                        return null;
                }       
        }
}
jonas
źródło
2
Oprócz używania C #, chciałbyś również użyć PlayerPrefs. Są one wieloplatformowe, nie możesz zrobić IO na Web / iOS / Android. unity3d.com/support/documentation/ScriptReference/... (Niezła próbka!)
TJHeuvel
PlayerPrefs są znacznie mniej elastyczne, są rzeczywiście wieloplatformowe i doskonale nadają się do przechowywania pojedynczych lub niepowiązanych wartości. Ale w Windows Player Prerefy są przechowywane w rejestrze jako zwykły tekst.
jonas
7
Jeśli już serializujesz, dlaczego nie serializować go do ciągu i przechowywać w PlayerPrefs. Pewnie, że jest mniej elastyczny, ale jest to właściwie jedyne rozwiązanie dla gry typu crosssplatform.
TJHeuvel
2
PlayerPrefs doskonale nadaje się do przechowywania niewielkich danych, takich jak ustawienia, ale dla całych zapisanych
gier
2
@TJHeuvel: „nie możesz zrobić IO w sieci / iOS / Android” Zdecydowanie możesz zrobić IO na telefonie komórkowym
Przemysław Wrzesiński
2

Dla niszczyciela prawdopodobnie zachowałbym wyłącznie między falami. W ten sposób musisz tylko pomyśleć o wieżach. Umieść kilka automatycznych punktów zapisu na poziomach, nie więcej niż 10 minut pomiędzy, ale prawdopodobnie lepiej jest mniej.

Oczywiście, jeśli twoje poziomy są wystarczająco krótkie, możesz po prostu zapisać tylko stan kampanii.

aaaaaaaaaaaa
źródło
1

Kiedy odnoszę się do bieżącego stanu gry, mam na myśli migawkę pamięci w momencie zapisywania. Musisz mieć możliwość odtworzenia tego z danych, które będziesz przechowywać na dysku twardym.

Najłatwiej jest po prostu serializować wszystkie klasy, które mają dane, które muszą być trwałe, i zrzucić je na dysk twardy, zasadniczo wykonując zrzut pamięci. Problem polega na tym, że zmiana twoich klas zmieni liczbę / typy wartości zserializowanych i złamie stare zapisy. Również dlatego, że zapisujesz wszystko, co wydłuża czas ładowania. Bardziej efektywne jest oznaczanie poszczególnych pól, które są rzeczywiście potrzebne do odbudowania bieżącej „migawki pamięci” za pomocą dowolnego systemu atrybutów używanego przez serializator / IDE. Następnie odbuduj „migawkę pamięci” z zapisanych danych.

Nigdy też nie korzystałem z Unity, więc może mieć coś wbudowanego. Jest to jednak typowe podejście.

ClassicThunder
źródło
masz na myśli, że muszę przechowywać moje stany w pliku?
Syed,
1
@ Tak, tak, pod koniec dnia należy go zapisać do jakiegoś pliku, ponieważ stan aplikacji nie zostanie zapisany w pamięci. W szczególności z Unity możesz użyć klasy PlayerPrefs (która, jak sądzę, faktycznie przechowuje rzeczy w rejestrze w systemie Windows), jeśli chcesz uniknąć odczytu / zapisu całego pliku.
Tetrad