Spielstatus speichern / laden?

12

Was ist die am häufigsten verwendete Methode oder der am häufigsten verwendete Algorithmus zum Speichern des Spielstatus (Profile)?

Ich habe gesehen, dass Caesar IV mySQL verwendet.

irgendwelche Vorschläge.

NativeCoder
quelle

Antworten:

20

Ich bin mir ziemlich sicher, dass dies meistens in einem proprietären (binären) Format geschieht, indem einfach jede Variable aus einer von Ihnen verwendeten Spielstatusstruktur in eine Datei geschrieben oder diese Datei in eine Instanz der Struktur zurückgelesen wird. In C ++ können Sie beispielsweise ein Objekt wie ein Array von Bytes behandeln und es einfach in eine Datei fwrite () oder aus der Datei fread () und wieder in die Objektform umwandeln.

Wenn Sie Java oder eine andere Sprache verwenden, können Sie die Serialisierung verwenden , um die Aufgabe wirklich zu vereinfachen. Die Java-Erklärung befindet sich am Ende dieser Antwort. Andere Sprachen (höher als C ++) haben sicherlich ihre eigenen Serialisierungsbibliotheken oder integrierten Funktionen, die Sie verwenden sollten. Unabhängig davon, wie ineffizient die Serialisierungsroutine sein mag, ist der Festplattenspeicher heutzutage günstig, insbesondere wenn der Spielstatus nicht sehr groß sein sollte, und verhindert, dass Sie eigene Serialisierungsroutinen schreiben und verwalten können.

Sie sollten auf keinen Fall MySQL verwenden (lesen Sie einfach den ersten Satz dieser Rezension ). Wenn Sie aus irgendeinem Grund wirklich eine relationale Datenbank benötigen , verwenden Sie SQLite . Es ist ein leichtgewichtiges Datenbanksystem und existiert in einer einzelnen Datenbankdatei. Bei den meisten Spielen sind relationale Datenbanken jedoch nicht der richtige Weg, und Unternehmen, die versuchen, sie zu verwenden, verwenden sie in der Regel eher als Nachschlagetabelle für Schlüsselwerte als als echte relationale Datenbanken.

Jede Art der Verschlüsselung lokaler Festplattendateien ist nur eine Verschleierung . Jeder Hacker schnüffelt die Daten sofort, nachdem Ihr Programm sie entschlüsselt hat. Ich persönlich bin gegen so etwas, INSBESONDERE gegen Einspieler-Spiele. Meiner Ansicht nach sollten die Besitzer des Spiels (wohlgemerkt zahlende Kunden) das Spiel hacken dürfen, wenn sie wollen. In einigen Fällen kann dies zu einem größeren Gemeinschaftsgefühl führen und es können "Mods" für Ihr Spiel entwickelt werden, die mehr Kunden zu Ihnen bringen. Das jüngste Beispiel, das mir in den Sinn kommt, ist das Portal in Minecraft , das kürzlich veröffentlicht wurde. Es wird auf den Websites der Spielernachrichten im Internet veröffentlicht, und Sie können wetten, dass es die Verkäufe von Minecraft steigerte.


Wenn Sie aus irgendeinem Grund verrückt genug sind, Java für die Spieleentwicklung zu verwenden, wie ich es bin, finden Sie hier eine kurze Erklärung zur Serialisierung in Java:

Halten Sie alle Ihre Spielstatusdaten in einer Klasse, machen Sie die Klasse durch Implementierung serialisierbar Serializable, verwenden Sie das transientSchlüsselwort, wenn Sie spezielle instanziierte Variablen in die Klasse mischen (transiente Objekte werden nicht serialisiert), und verwenden Sie einfach ObjectOutputStream, um in eine Datei zu schreiben und ObjectInputStreamaus einer Datei zu lesen . Das ist es.

Ricket
quelle
2
Hehe, The Witcher hat ihre Daten nicht verschlüsselt. Sehr einfach, die gespeicherte Spieldatei in einem Hex-Editor zu öffnen, ein bisschen damit herumzuspielen und alle nackten Chick-Karten zu bekommen ... Oh Gott, es tut mir so leid!
Anthony
Ich habe die binäre .NET-Serialisierung zum Speichern von Spielen verwendet, und C # ist möglicherweise eine etwas vernünftigere Plattform als Java, um Spiele zu entwickeln. Mir gefällt, wie automatisch ein ganzes Objektdiagramm gespeichert wird. Das war früher viel schwieriger. Natürlich gibt es jetzt die Herausforderung, unnötige Teile wie die Texturen auszuschließen, aber das ist keine große Sache.
BlueMonkMN
Ich bin nicht anderer Meinung, dass C # für die Entwicklung von Spielen etwas beliebter ist als Java. Vernünftiger impliziert eine gewisse Subjektivität, und als Entwickler von XNA und Java bevorzuge ich Java. Wenn Sie möchten, können Sie auch Anweisungen zur Serialisierung in C # auflisten. Ich habe das noch nie getan, kann es aber in meine Antwort ändern. Durch die Serialisierung von Java wird der gesamte Objektgraph gespeichert, und das Schlüsselwort 'transient' für Variablen schließt unnötige Teile wie Texturen aus. Alle nicht transienten Member müssen serialisierbar sein. Andernfalls können Sie eine benutzerdefinierte writeObject-Methode schreiben, um dies zu umgehen.
Ricket
Pythons Pickle speichert auch ein gesamtes Objektdiagramm für Sie und ist einfach zu bedienen. Wenn es Zeit für die Deserialisierung ist, werden Ihnen vollständig hydratisierte Objekte einfach zurückgegeben: docs.python.org/library/pickle.html
drhayes
Wenn Sie den integrierten Binärformatierer verwenden, können Sie bestimmte Felder in C # /. NET einfach von der Serialisierung ausschließen, indem Sie sie mit dem Attribut [NonSerialized] versehen. Es ist jedoch leicht zu übersehen, dass vom Compiler generierte Ereignisse (dh Ereignisse ohne benutzerdefinierte Operatoren zum Hinzufügen / Entfernen) ein Hintergrundfeld zum Speichern ihrer Abonnenten erstellen. Somit ist es einfach, Ereignishandler versehentlich (und unwissentlich) in ein serialisiertes Objektdiagramm aufzunehmen. Um dies zu umgehen, müssen Sie das NonSerialized-Attribut zur Ereignisdeklaration hinzufügen, aber Sie müssen das "field:" - Qualifikationsmerkmal hinzufügen:[field: NonSerialized]
Mike Strobel
3

Wenn Sie Ihren eigenen Code schreiben, beispielsweise in C ++, können Sie Binärdateien verwenden. Binärdateien bieten Ihnen eine Form der Verschlüsselung durch Verschleierung. Aber wie überall im Internet dokumentiert, ist dies eine sehr schwache Form der Sicherheit.

ODER Sie können so etwas wie RapidXML verwenden, wenn Sie eine für Menschen lesbare Lösung wünschen.

Wenn Sie ein Framework verwenden, sehen Sie sich dessen Dateisupportfunktionen an. HTH

JustBoo
quelle
0

Die meisten Spiele, die ich gesehen habe, verwenden nur handgeschriebenen Code zum Lesen / Schreiben von Binärdateien. Das On-Disc-Format ist häufig eine exakte Kopie des Speicherlayouts eines Objekts.

  1. Datei in den Speicher einlesen.
  2. Zeiger auf Puffer auf Objekttyp umwandeln.

Es ist schnell, aber aufwändig zu warten, plattformspezifisch und unflexibel.

In letzter Zeit haben einige Spiele SQLite verwendet. Die Leute, mit denen ich gesprochen habe, scheinen es zu mögen.

herrlich
quelle
0

Die Serialisierung wird in einigen anderen Antworten erwähnt, und ich stimme zu, dass dies eine vernünftige Lösung ist. Eine Möglichkeit, die fehlschlägt, ist die Versionierung.

Nehmen wir an, Sie veröffentlichen Ihr Spiel und die Leute spielen es und erstellen einige gespeicherte Spiele. Dann möchten Sie in einem späteren Patch einen Fehler beheben oder einige Funktionen hinzufügen. Wenn Sie eine einfache binäre Serialisierungsmethode verwenden und Ihren Klassen ein Mitglied hinzufügen, ist Ihre Serialisierung möglicherweise nicht mit den alten Speicherspielen kompatibel, wenn die Kunden Ihren Patch installieren.

Egal welchen Ansatz Sie verwenden, denken Sie an dieses Problem, bevor Sie das Spiel zum ersten Mal veröffentlichen! Kunden werden nicht glücklich sein, wenn sie nach dem Anwenden eines Patches von vorne beginnen müssen.

Eine Möglichkeit, dies zu vermeiden, besteht darin, dass jeder Basisdatentyp die Methoden Save (Version) und Load (Version) implementiert, die intelligent genug sind, um zu wissen, welche Daten für jede Version des Spiels gespeichert und geladen werden müssen. Auf diese Weise können Sie die Abwärtskompatibilität Ihrer gespeicherten Spiele unterstützen und ordnungsgemäß fehlschlagen, wenn ein Benutzer versucht, ein gespeichertes Spiel aus einer neueren Version des Spiels zu laden, als sie ausgeführt werden.

kevin42
quelle
1
Als kurze Anmerkung: Das Implementieren von "Speichern" - und "Laden" -Funktionen für jede Version des Spiels wird schnell zu einem Wartungs-Albtraum. Ich habe herausgefunden, dass eine bessere Lösung darin besteht, eine Versionsnummer einzubetten, "Speichern / Laden" -Funktionen für die aktuelle Version des Spiels zu schreiben und eine "Konvertierungs" -Funktion von der neuesten nicht aktuellen Version in die aktuelle Version zu schreiben. Behalten Sie dann einfach alle Ihre Konvertierungsfunktionen bei. Der Versuch, ein 10-Versions-altes Spiel zu laden, würde zehn Konvertierungsfunktionen in Serie ausführen, dann die native Funktion "Aktuelle Spielversion laden".
ZorbaTHut
Langfristig viel einfacher zu warten - das Speichern einer Reihe von Funktionen zum Laden aller vorherigen Spieledateien wird schnell zu einer Operation in Polynomzeit.
ZorbaTHut
In Spielen, an denen ich gearbeitet habe, ist es nicht so komplex - anstatt mehrere Kopien der Lade- / Speichermethoden zu speichern, verwendet die eine einzelne Methode die Versionsnummer, um zu bestimmen, welche Bytes gelesen und geschrieben werden sollen. Dies wird noch einfacher, wenn Sie nicht nur Strukturen schreiben, sondern das Laden und Speichern als Operationen auf der Ebene des primitiven Datentyps implementieren (z. B. ReadByte / ReadFload / etc). Wenn Sie dann ein neues Mitglied hinzufügen, können Sie so etwas tun wie if (Version> 10) {someNewByte = ReadByte (); } Die Implementierung auf diese Weise erleichtert auch die Unterstützung verschiedener Endian-Plattformen.
Kevin42
Eine andere Möglichkeit, die Unterstützung der Versionsverwaltung nicht zu verbessern, besteht darin, zu vermeiden, dass die Serialisierungs- / Deserialisierungsmethoden Ihrer Objekte einzelne Werte direkt aus einem Stream schreiben / lesen. Stattdessen könnten Objekte ihre eigenen Daten mithilfe von Schlüssel / Wert-Paaren in einen Eigenschaftsbeutel schreiben und den Beutel dann in den Stream ausgeben. Während der Deserialisierung konnten Objekte Werte anhand des Namens aus dem Beutel lesen. Anstatt jedoch bestimmte Versionsnummernprüfungen wie bei kevin42 vorschlagen zu lassen, können Sie auch Regeln für den Umgang mit fehlenden Werten festlegen (dh einen Standardwert verwenden, wenn der erforderliche Wert nicht in der Tasche enthalten ist).
Mike Strobel
0

Wenn Sie dasselbe Format verwenden können, in dem Sie Ihre Level gespeichert haben, ist dies ein Bonus.

Zum Beispiel könnte ein Spiel wie Peggle ein anfängliches Brettlayout, eine Anzahl von Bällen, eine aktuelle Punktzahl (0 für das anfängliche Brett) usw. haben. Dann kann ein gespeichertes Spiel genau dasselbe Format verwenden.

Wenn Sie dasselbe Format verwenden, können das gespeicherte Spiel und das Laden des Levels Code gemeinsam nutzen, um Ihre Arbeit zu erleichtern!

Bei einem Spiel mit sehr großen Kartendateien kann das gespeicherte Spiel die Kartendatei als Referenz enthalten. Die Dateien der ersten Ebene könnten das Gleiche tun, was es auch einfacher macht, zu dieser Karte zurückzukehren, wenn der Charakter aus irgendeinem Grund an den gleichen Ort zurückkehrt, mit der Ausnahme, dass einige der NPCs tot sind und alle Leichen liegen Über.

Zan Lynx
quelle