Spielstände speichern und laden

Aus Spieleprogrammierer-Wiki
(Unterschied zwischen Versionen)
Wechseln zu: Navigation, Suche
[unmarkierte Version][gesichtete Version]
K (Die Werte F,G und Optionale Werte)
(Das Dateiformat des Spielstandes)
 
(112 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
== Was ist A-Stern? ==
+
{{Baustelle}}
[[Datei:A-Stern_Anim1.gif|thumb|left|150px|Optimaler Weg zum Ziel]]
+
[[Kategorie:Game-Design]]
<br/>
+
A-Stern ist ein Algorithmus um den kürzesten oder kostengünstigsten Weg zwischen 2 Punkten zu finden.<br/>
+
Dafür verwendet er eine Schätzfunktion, die dazu beiträgt gerichtet zu suchen. Gibt es einen Weg zwischen den 2 Punkten findet A-Stern ihn. <br/>
+
<br/>
+
<br/>
+
<br/>
+
<br/>
+
<br/>
+
<br/>
+
  
== Wo findet A-Stern Verwendung? ==
+
Die Speicherfunktion in Spielen mag auf den ersten Blick trivial erscheinen, ist sie aber bei Weitem nicht. Die Art und Weise wie das Spiel gespeichert werden kann, nimmt starken Einfluss auf die Motivation des Spielers. Sind die Spielabschnitte zu groß ohne dass der Spieler abspeichern kann, führt das schnell zu Frustration, weil der Spieler immer wieder von vorne anfangen muss. Im Gegensatz dazu kann eine immer und überall verfügbare Speicherfunktion das Spiel zu leicht machen, und auch das kann dazu führen, dass der Spielspaß leidet. Aus diesen Gründen sollte man sich bewusst Gedanken über die Speicherfunktion seines Spiels machen.
Im Prinzip kann A-Stern überall da verwendet werden wo Spielobjekte (z.B eigene Spielfigur oder Gegner) von A nach B müssen, auf nicht vorgefertigten Wegen. <br/>
+
{| class="wikitable"
+
|+ Beispiele an Hand von Spielen
+
! Genre !! Spiele Vertreter !! im Detail
+
|-
+
| Echtzeitstrategie
+
| Command and Conquer
+
| eigene/gegnerische Einheiten
+
|-
+
| runden basiertes Strategiespiel
+
| Civilization
+
| eigene/gegnerische Einheiten
+
|-
+
| Ego Shooter
+
| Half Life
+
| gegnerische Einheiten
+
|-
+
| MMORPG
+
| World of Warcraft
+
| eigene Begleiter/gegnerische Einheiten
+
|}
+
  
== Wichtige Bestandteile von A-Stern ==
+
== Arten Spielstände zu speichern  ==
Hier wird auf die wichtigsten Komponenten des Algorithmus eingegangen, weil diese Begriffe später immer wieder auftauchen.
+
=== Die Knoten ===
+
Als Knoten wird in diesem Zusammenhang ein Element des Spielfeldes bezeichnet. Sie können Verschiedene Geometrische Formen annehmen Viereckig, Sechseckig oder Achteckig. Diese Knoten können in manchen Spielen auch gar keine sichtbare Formen annehmen aber sie Existieren auf jeden Fall irgendwo in form von Code.<br/>
+
<br/>
+
Es gibt verschiedene Arten von Knoten:
+
* unbekannte Knoten
+
* bekannte Knoten
+
* untersuchte Knoten
+
  
Ein unbekannter Knoten muss dem A-Stern Algorithmus erst im laufe der Zeit bekannt gemacht werden. Bekannte Knoten können untersucht werden. Durch diese Untersuchung können unbekannt Knoten entdeckt werden. Diese unbekannten Knoten werden analysiert und werden zu bekannten Knoten. Wenn der bekannte Knoten einmal untersucht wurden, bleibt es dabei und er wird nicht noch einmal untersucht. Allerdings können bekannte Knoten öfters Analysiert werden.
+
In diesem Abschnitt gibt es einen Überblick über die Möglichkeiten Spielfortschritte zu speichern.
  
=== Die Schätzfunktion H===
+
=== Level-Code ===
Die Schätzfunktion wird benötigt um dem aktuell untersuchten Knoten einen Wert zu zuweisen. Dieser Wert macht darüber eine Aussage wie weit weg der Knoten ca. vom Ziel entfernt ist.<br/><br/>
+
Eine sehr einfache Methode den Spielfortschritt festzuhalten ist der Level-Code. Solch ein Code besteht meistens aus Zahlen, Buchstaben oder (Spiel-)Symbolen. Er fand besonders zu Beginn der Spieleentwicklung oft Verwendung in Jump and Run-Spielen, Denkspielen oder Strategiespielen. Typische Vertreter sind [http://de.wikipedia.org/wiki/Mega_lo_Mania Mega lo Mania], [http://de.wikipedia.org/wiki/Battle_Isle Battle Isle], [http://de.wikipedia.org/wiki/Pushover Push Over] oder [http://de.wikipedia.org/wiki/Gods Gods].
Es gibt verschiedene Ansätze für die Schätzfunktion und es hängt auch immer davon ab was genau erreicht werden soll im späteren Programm.<br/>
+
Die Berechnung der direkten Distanz zwischen dem Aktuellen Knoten und dem Ziel ist eine Möglichkeit. Diese Distanz wird mittels des Pythagoras ermittelt. Eine weitere Möglichkeit ist die Manhattan Distanz. Bei dieser Methode werden vom entstehenden Dreieck einfach die Längen der beiden Seiten a und b Addiert.
+
[[Datei:A-Stern_Distanz1.gif|left|Entfernungen zum Schätzen bestimmen]]<br/>
+
<big>'''Nach Pythagoras :'''</big><br/>
+
<math>Distanz = \sqrt {{X_{Laenge}}^2 + {Y_{Laenge}}^2} = \sqrt { 5^2 + 8^2 } = 9,4 </math><br/><br/>
+
<big>'''Manhattan Distanz :'''</big><br/>
+
<math>Distanz = X_{Laenge} + Y_{Laenge} = 5 + 8 = 13 </math><br/>
+
<br/>
+
Da der Wert für die Schätzfunktion im allgemeinen als H bezeichnet wird werde ich mich ebenso daran halten.<br/>
+
Das H wird im späteren Verlauf immer wieder auftauchen.<br/>
+
<br/>
+
<br/>
+
<br/>
+
  
=== Die Werte F, G und optionale Werte ===
+
In der Regel wird für jeden durchgespielten Level ein Code freigeschaltet. Möchte der Spieler das Spiel fortsetzen, so gibt er den entsprechenden Code ein. Genau genommen wird hierbei nichts gespeichert. Gewissermaßen wird das Speichern der Daten auf den Spieler ausgelagert, der sich den Code auf einem Zettel oder in einer Datei merkt. Darum wurde diese Methode oft von Konsolenspielen angewendet, die (aus Kostengründen) keinen wiederbeschreibbaren Speicher auf ihrer Catridge zur Verfügung hatten. Es ist möglich, im Level-Code gewisse einfache Informationen wie die Punktzahl des Spielers versteckt zu kodieren (eine Prüfsumme schützt gegen einfache Manipulationsversuche). Auch für Spiele, die keine Daten auf dem Rechner des Spielers ablegen möchten oder dürfen, ist der Level-Code eine Alternative (z. B. Flash-Spiele).
Eng verbunden mit der Schätzfunktion sind 2 weitere Werte. Der Wert für den bereits zurückgelegten Weg vom Startknoten. Dieser Wert wird genau berechnet und im allgemeinen als G Bezeichnet. Ein Weiterer wichtiger Wert ist die Summe aus H und G. Dieser Wert wird allgemein F genannt. Er stellt später das Suchkriterium dar, nach dem aus der Openlist ein Knoten ausgewählt wird.<br/>
+
<br/>
+
Es gibt auch weitere Werte die Einfluss haben könnten auf den Algorithmus. Zum Beispiel extra Kosten die bei Strategiespielen durch unwegsames Gelände zustande kommen. Eine weitere Möglichkeit sind auch Drehbewegung einer Spielfigur die auch Kosten verursachen können. Es gibt bestimmt noch unzählige weitere Dinge die Einfluss nehmen können auf den Algorithmus. <br/>
+
<br/>
+
Diese Optionalen Werte sollten auch mit in die Rechnung für F einfließen.<br/>
+
Berechnungs Formel: <math>F = H + G + Optional</math> <br/>
+
  
=== Die Openlist ===
+
Die Vorteile von Level-Codes liegen in der einfachen Implementierung und darin, dass keine Daten auf dem Rechner abgelegt werden müssen. Der Spieler kann seinen Spielstand von überall aus wiederherstellen, solange er den Level-Code kennt.
In die Openlist kommen alle Knoten die bekannt sind. Bei der Openlist kann es sich um eine [http://de.wikipedia.org/wiki/Liste_%28Datenstruktur%29 Verkettete Liste] oder einem [http://de.wikipedia.org/wiki/Feld_%28Datentyp%29 Array] handeln. In dieser List können die Knoten nach ihren F werten sotiert werden. Somit kann schneller auf den erfolgversprechendsten Knoten zugegriffen werden.
+
  
=== Die Closedlist ===
+
Der Hauptnachteil von Level-Codes ist ihre geringe Flexibilität. Es können nur sehr wenige zusätzliche Informationen in einem Level-Code untergebracht werden, wenn seine Länge begrenzt ist. Die Länge ist dadurch praktisch begrenzt, dass der Spieler den Code meist per Hand aufschreiben und später wieder eingeben muss.
In die ClosedList kommen alle Knoten die bereits untersucht wurden. Bei diese Liste handelt es sich ebenfals um eine [http://de.wikipedia.org/wiki/Liste_%28Datenstruktur%29 Verkettete Liste] oder einem [http://de.wikipedia.org/wiki/Feld_%28Datentyp%29 Array]. Die Reihenfolge in der Closedlist spielt keine Rolle.
+
  
== Arbeitsweise von A-Stern ==
+
=== Speicherpunkte ===
Hier wird jetzt beschrieben wie alle Komponenten des Algorithmus zusammen arbeiten. <br/>
+
Speicherpunkte geben dem Spieler die Möglichkeit, den aktuellen Spielstand, nur an bestimmten Stellen des Spiels zu speichern. Die Implementierung in das Spiel kann dabei aber sehr unterschiedlich sein. Eine Variante kann z. B. sein, wie im Spiel [http://de.wikipedia.org/wiki/Final_Fantasy_XII Final Fantasy XII], an gewissen Stellen in einer frei begehbaren Spielwelt Speicherpunkte zu setzen. Eine andere Variante könnte es sein, den Spieler zu fragen, ob er nach einem gewissen Levelabschnitt abspeichern möchte, wie im Spiel [http://de.wikipedia.org/wiki/Super_Mario_World Super Mario World].
=== Datenstrukture eines Knoten ===
+
Diese Werte sollte ein Knoten mindestens Speichern können.
+
*H - Beinhaltet den Schätzwert
+
*G - Zurückgelegte Weg Kosten
+
*F - Summe aus G und H
+
*Coord_X - X Koordinate des Knoten
+
*Coord_Y - Y Koordinate des Knoten
+
*ComeFrom_X - X Koordinate des Knoten von dem auf den aktuellen Knoten zugegriffen wurde
+
*ComeFrom_Y - Y Koordinate des Knoten von dem auf den aktuellen Knoten zugegriffen wurde
+
<br/>
+
Vielleicht auch noch 2 zusätzliche Flags:
+
*isOpenList
+
*isClosedList
+
Das erspart dann lästige vergleiche zwischen den 2 listen ob ein Knoten schon in der Closedlist ist.
+
=== Beschreibung ===
+
Zu begin sind nur 2 Knoten dem Algorithmus bekannt, der Startknoten und der Zielknoten. Der Startknoten wird der Openlist zugefügt. Den Zielknoten behalten wir erstmal nur im Hinterkopf.<br/>
+
<br/>
+
In der Openlist wird nun nach dem geeignetesten Knoten gesucht. Da hier nur der Startknoten drin steht fällt die Wahl nicht schwer. Jetzt wird der Startknoten untersucht, das bedeutet das nach allen benachbarten Knoten gesucht wird. Für jeden gefundenen Knoten werden die Werte für H, G und F ermittelt. Die ermittelten Werte werden natürlich in den jeweiligen Knoten gespeichert. Weiterhin muss auch gespeichert von welchem Knoten man auf den neuen Knoten gekommen ist. Die neu gefunden Knoten kommen alle in die Openlist. Der Startknoten wird von einem bekannten Knoten nun zu einem untersuchten Knoten und kommt damit in die ClosedList.<br/>
+
<br/>
+
Jetzt wird in der Openlist nach dem Knoten gesucht der den geringsten F Wert hat. Von diesem Knoten werden nun wieder alle benachbarten Knoten gesucht und analysiert. Dabei kann es vorkommen das im laufe der Zeit Knoten die schon in der Openlist stehen nochmal analysiert werden. Wenn der F wert sich verbessert sollten alle Daten des Knoten Überschrieben werden. Sind die Daten gleich oder schlechter können die alten Daten beibehalten werden.<br/>
+
<br/>
+
So arbeitet der Algorithmus die Openlist ab, fügt unbekannte Knoten der Openlist zu und fügt untersuchte Knoten der Closedlist zu. Wenn jetzt der Zielknoten der Closedlist zugefügt wird ist es vollbracht. Der günstigste weg ist gefunden.<br/>
+
<br/>
+
Nun kann ausgehend vom Zielknoten geschaut werden von welchem Knoten man auf den Zielknoten kamm. Von dem wird dann geschaut von welchem Knoten man auf diesen kamm und immer so weiter bis man wieder am Startknoten angekommen ist. So wird dann der beste Weg abgebildet.<br/>
+
<br/>
+
Wenn die Openlist leer ist bevor man den Zielknoten erreicht hat kann der Algorithmus abgebrochen werden, da dann kein Weg zwischen Start- und Zielnoten existiert.
+
  
=== Step by Step mit Bildern ===
+
In jedem Fall sollte bei dieser Methode darauf geachtet werden, dass ausreichend Speicherpunkte vorhanden sind.
Da Bilder mehr sagen als 1000 Worte nochmal alles in Bildern erklärt. <br/>
+
Es sind keine Diagonalen Schritte erlaubt. Die Distanz zum Ziel wird mit hilfe der Manhattan Distanz bestimmt. Die Kosten für einen Schritt betragen 1 Punkt. Um Treppenartige Wege zu verhinden wird ein Richtungs Wechsel auch ein Punkt kosten. Die Knoten werden nach ihren Koordinaten benannt (X Koordinate zuerst).<br/>
+
<br/>
+
Spielfeld Legende:
+
* grün - Startpunkt (10/7)
+
* Orange - Zielpunkt (2/2)
+
* weiß - unbekannte Knoten
+
* gelb - bekannte Knoten (OpenList)
+
* blau - untersuchte Knoten (ClosedList)
+
* schwarz - nicht begehbare Knoten
+
<br/>
+
[[Datei:A-Stern_Step_by_Step.gif]]
+
<br/>
+
{| class="wikitable"
+
|+
+
| colspan="6"| OpenList
+
|-
+
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 1
+
| (10/7)
+
| 13
+
| 0
+
| 0
+
| 13
+
|
+
| N/A
+
| N/A
+
|}
+
{| class="wikitable"
+
|+
+
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 2
+
| (10/6)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (9/7)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
|
+
|
+
|-
+
|
+
| (10/8)
+
| 14
+
| 1
+
| 0
+
| 15
+
|
+
|
+
|
+
|-
+
|}
+
{| class="wikitable"
+
|+
+
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 3
+
| (10/5)
+
| 11
+
| 2
+
| 0
+
| 13
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (9/7)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
| (10/6)
+
| (10/7)
+
|-
+
|
+
| (9/6)
+
| 12
+
| 1
+
| 1
+
| 14
+
|
+
|
+
|
+
|-
+
|
+
| (10/8)
+
| 14
+
| 1
+
| 0
+
| 15
+
|
+
|
+
|
+
|}
+
{| class="wikitable"
+
|+
+
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 4
+
| (10/4)
+
| 10
+
| 3
+
| 0
+
| 13
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (9/7)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
| (10/6)
+
| (10/7)
+
|-
+
|
+
| (9/5)
+
| 11
+
| 2
+
| 1
+
| 14
+
|
+
| (10/5)
+
| (10/6)
+
|-
+
|
+
| (9/6)
+
| 12
+
| 1
+
| 1
+
| 14
+
|
+
|
+
|
+
|-
+
|
+
| (10/8)
+
| 14
+
| 1
+
| 0
+
| 15
+
|
+
|
+
|
+
|}
+
{| class="wikitable"
+
|+
+
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 5
+
| (10/3)
+
| 9
+
| 4
+
| 0
+
| 13
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (9/7)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
| (10/6)
+
| (10/7)
+
|-
+
|
+
| (9/4)
+
| 10
+
| 3
+
| 1
+
| 14
+
|
+
| (10/5)
+
| (10/6)
+
|-
+
|
+
| (9/5)
+
| 11
+
| 2
+
| 1
+
| 14
+
|
+
| (10/4)
+
| (10/5)
+
|-
+
|
+
| (9/6)
+
| 12
+
| 1
+
| 1
+
| 14
+
|
+
|
+
|
+
|-
+
|
+
| (10/8)
+
| 14
+
| 1
+
| 0
+
| 15
+
|
+
|
+
|
+
|}
+
  
{| class="wikitable"
+
==== Freies Speichern ====
|+
+
Unter freiem Speichern versteht man, dass der Spieler grundsätzlich zu jeder Zeit und an jedem Ort im Spiel abspeichern kann. Dies sollte aber einigen Einschränkungen unterliegen. In Zwischensequenzen oder anderen Teilen des Spiels, in dem der Spieler keine aktive Kontrolle hat, sollte es dem Spieler nicht möglich sein das Spiel zu speichern.
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 6
+
| (10/2)
+
| 9
+
| 4
+
| 0
+
| 13
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (9/7)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
| (10/6)
+
| (10/7)
+
|-
+
|
+
| (9/3)
+
| 9
+
| 4
+
| 1
+
| 14
+
|
+
| (10/6)
+
| (10/5)
+
|-
+
|
+
| (9/4)
+
| 10
+
| 3
+
| 1
+
| 14
+
|
+
| (10/4)
+
| (10/5)
+
|-
+
|
+
| (9/5)
+
| 11
+
| 2
+
| 1
+
| 14
+
|
+
| (10/3)
+
| (10/4)
+
|-
+
|
+
| (9/6)
+
| 12
+
| 1
+
| 1
+
| 14
+
|
+
|
+
|
+
|-
+
|
+
| (10/8)
+
| 14
+
| 1
+
| 0
+
| 15
+
|
+
|
+
+
|}
+
  
{| class="wikitable"
+
Dem Spieler könnten aber noch mehr Beschränkungen auferlegt werden, z. B.:
|+
+
*Nur in bestimmten Gebieten ist das Speichern möglich.
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
*In bestimmten Gebieten ist das Speichern ''nicht'' möglich.
|-
+
*Nur eine bestimmte Anzahl von Speicherungen möglich.
| 7
+
| (9/7)
+
| 12
+
| 1
+
| 0
+
| 13
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (9/2)
+
| 8
+
| 5
+
| 1
+
| 14
+
|
+
| (10/6)
+
| (10/7)
+
|-
+
|
+
| (9/3)
+
| 9
+
| 4
+
| 1
+
| 14
+
|
+
| (10/6)
+
| (10/5)
+
|-
+
|
+
| (9/4)
+
| 10
+
| 3
+
| 1
+
| 14
+
|
+
| (10/4)
+
| (10/5)
+
|-
+
|
+
| (9/5)
+
| 11
+
| 2
+
| 1
+
| 14
+
|
+
| (10/3)
+
| (10/4)
+
|-
+
|
+
| (9/6)
+
| 12
+
| 1
+
| 1
+
| 14
+
|
+
| (10/2)
+
| (10/3)
+
|-
+
|
+
| (9/1)
+
| 9
+
| 6
+
| 0
+
| 15
+
|
+
|
+
|
+
|-
+
|
+
| (10/8)
+
| 14
+
| 1
+
| 0
+
| 15
+
|
+
|
+
+
|}
+
... <br/>
+
Wer üben will kann ja Schritt 8 und folgende an Hand der Animation selber mal machen. <br/>
+
Ich spring jetzt gleich zum letzten Schritt um zu zeigen wie man jetzt den Weg ab gehen kann.<br/>
+
...
+
  
{| class="wikitable"
+
==== Normales Speichern ====
|+
+
Das normale Speichern erfolgt meistens über ein Menü. Dort können dann alte Spielstände überschrieben werden oder neue Spielstände angelegt werden und ihnen ein eigener Name gegeben werden.
! Schritt !!Knotenname !! H !! G !! Z !! F !! __ !! Knotenname !! ComeFrom
+
|-
+
| 21
+
| (6/3)
+
| 5
+
| 8
+
| 1
+
| 14
+
|
+
| (10/7)
+
| N/A
+
|-
+
|
+
| (1/7)
+
| 6
+
| 8
+
| 0
+
| 14
+
|
+
| (10/6)
+
| (10/7)
+
|-
+
|
+
| (6/5)
+
| 7
+
| 6
+
| 1
+
| 14
+
|
+
| (10/6)
+
| (10/5)
+
|-
+
|
+
| (9/3)
+
| 8
+
| 5
+
| 1
+
| 14
+
|
+
| (10/4)
+
| (10/5)
+
|-
+
|
+
| (6/6)
+
| 8
+
| 5
+
| 1
+
| 14
+
|
+
| (10/3)
+
| (10/4)
+
|-
+
|
+
| (9/4)
+
| 9
+
| 4
+
| 1
+
| 14
+
|
+
| (10/2)
+
| (10/3)
+
|-
+
|
+
| (7/6)
+
| 9
+
| 4
+
| 1
+
| 14
+
|
+
| (10/8)
+
| (10/7)
+
|-
+
|
+
| (9/5)
+
| 10
+
| 3
+
| 1
+
| 14
+
|
+
| (8/7)
+
| (9/7)
+
|-
+
|
+
| (8/6)
+
| 10
+
| 3
+
| 1
+
| 14
+
|
+
| (7/7)
+
| (8/7)
+
  
|-
+
==== Quicksave ====
|
+
Die Quicksave-Funktion speichert das Spiel komfortabel über eine Taste oder Tastenkombination ab. Das ermöglicht dem Spieler eine schnelle Speicherung ohne den Spielfluss zu unterbrechen. Meistens ist für diese Funktion ein bestimmter Speicherplatz reserviert, der dann immer wieder überschrieben wird.
| (9/6)
+
| 11
+
| 2
+
| 1
+
| 14
+
|
+
| (6/7)
+
| (7/7)
+
|-  
+
|
+
| (10/8)
+
| 14
+
| 0
+
| 0
+
| 14
+
|
+
| (5/7)
+
| (6/7)
+
|-
+
|
+
| (2/8)
+
| 6
+
| 8
+
| 1
+
| 15
+
|
+
| (4/7)
+
| (5/7)
+
|-
+
|
+
| (3/8)
+
| 7
+
| 7
+
| 1
+
| 15
+
|
+
| (3/7)
+
| (4/7)
+
|-
+
|
+
| (4/8)
+
| 8
+
| 6
+
| 1
+
| 15
+
|
+
| (2/7)
+
| (3/7)
+
|-
+
|
+
| (5/8)
+
| 9
+
| 5
+
| 1
+
| 15
+
|
+
| (9/2)
+
| (10/2)
+
|-
+
|
+
| (6/8)
+
| 10
+
| 4
+
| 1
+
| 15
+
|
+
| (8/2)
+
| (9/2)
+
|-
+
|
+
| (7/8)
+
| 11
+
| 3
+
| 1
+
| 15
+
|
+
| (2/6)
+
| (2/7)
+
|-
+
|
+
| (8/8)
+
| 12
+
| 2
+
| 1
+
| 15
+
|
+
| (2/5)
+
| (2/6)
+
|-
+
|
+
| (9/8)
+
| 13
+
| 1
+
| 1
+
| 15
+
|
+
| (2/4)
+
| (2/5)
+
  
|-  
+
==== Autosave ====
|
+
Die Autosave-Funktion speichert das Spiel automatisch. Dies kann erfolgen, wenn im Spiel ein Gebiet/Level verlassen wird und ein Neues betreten wird. Es kann auch nach einem bestimmten Zeitintervall gespeichert werden oder aber auch nach einem bestimmten Ereignis im Spiel. Oft deutet ein Autosave-Punkt darauf hin, dass in Kürze eine besonders schwierige Situation folgen wird und zu erwarten ist, dass der Spieler daran scheitert. Somit können Autosave-Punkte auch gezielt eingesetzt werden, um das Spielerlebnis des Spielers zu prägen.
| (3/3)
+
| 2
+
| 13
+
| 1
+
| 16
+
|
+
| (2/3)
+
| (2/4)
+
  
|-
+
== Speicherfunktion als Teil des Spielkonzepts ==
|
+
Der Schwierigkeitsgrad eines Spiels kann auch durch die Speicherfunktion beeinflusst werden. In einem Rollenspiel zum Beispiel kann das Abspeichern, im Schwierigkeitsgrad "leicht", immer und überall erfolgen. Wechselt der Spieler jedoch in den Schwierigkeitsgrad "mittel", kann es z. B. nur noch in gewissen Gebieten im Spiel möglich sein abzuspeichern. Im Schwirigkeitsgrad "schwer" wird das Spiel dann nur noch beim Beenden des Spiels gespeichert. All das lässt sich natürlich auch auf andere Genres übertragen.
| (1/3)
+
| 2
+
| 13
+
| 1
+
| 16
+
|
+
| (2/2)
+
| (2/3)
+
  
|-
+
== Die Ladefunktion ==
|
+
| (3/4)
+
| 3
+
| 12
+
| 1
+
| 16
+
|
+
|
+
|
+
  
|-
+
Die Ladefunktion hat die Aufgabe, den gespeicherten Spielstand einzulesen, auf Gültigkeit zu überprüfen (beschädigte oder manipulierte Daten sollten erkannt werden) und ihn wiederherzustellen. Wie dies konkret umgesetzt wird, hängt selbstverständlich vom jeweiligen Spiel ab.
|
+
| (1/4)  
+
| 3
+
| 12
+
| 1
+
| 16
+
|
+
|
+
|
+
  
|-
+
Die Möglichkeit, den Spielstand zu laden, sollte im Hauptmenü implementiert werden. So kann direkt nach Spielstart, ohne große Umwege, das Spiel geladen werden. Wenn es zum Spielkonzept passt, kann es auch eine Ladefunktion im eigentlichen Spiel geben, um schnell und bequem einen alten Spielstand wiederherzustellen.
|
+
| (3/5)
+
| 4
+
| 11
+
| 1
+
| 16
+
|
+
|
+
|
+
  
|-
+
== Das Dateiformat des Spielstandes ==
|
+
| (1/5)
+
| 4
+
| 11
+
| 1
+
| 16
+
|
+
|
+
|
+
  
|-
+
Worüber man sich auf jedenfall auch Gedanken machen muss, ist,  welches Dateiformat man verwenden will. Einen Aspekt dabei stellt die Manipulierbarkeit dar. Eine Manipulation bedeutet in dem Zusammenhang eine vom Entwickler ungewollte Veränderung der Spielstände. Es gibt grundsätzlich keinen Schutz, der mit einhundertprozentiger Sicherheit vor Manipulation schützt, aber durch die Wahl des richtigen Formats kann die Zeit verzögert werden, bis bekannt ist, wie die Spielstände aufgebaut sind und diese somit editiert werden können.
|
+
| (8/3)
+
| 7
+
| 8
+
| 1
+
| 16
+
|
+
|
+
|
+
  
|-
+
Eine Möglichkeit zum Schutz vor Manipulation stellt in der Regel das Verwenden einer Dateiendung, die nicht direkt auf den Dateityp schließen lässt, wie <tt>.sav</tt>. Bei textuellen Formaten dürfte dies kaum helfen, da der erste Versuch bei einer Manipulation in der Regel mit einem normalen Texteditor durchgeführt wird. Binäre Formate könnten sich beim Öffnen durch ihre [http://de.wikipedia.org/wiki/Magische_Zahl_(Informatik) magische Zahl] entlarven, sofern bei dem Dateityp eine solche verwendet wird.
|
+
| (8/1)  
+
| 7
+
| 8
+
| 1
+
| 16
+
|
+
|
+
+
  
|-  
+
Generell ist es natürlich immer möglich, die Spielstandsdaten zu verschlüsseln und/oder mit einer [http://de.wikipedia.org/wiki/Prüfsumme Prüfsumme] zu versehen. Das Entschlüsselungs-/Prüfsummenverfahren bzw. der Schlüssel müssen jedoch irgendwo im Programm gespeichert werden. Verschlüsselung und Prüfsumme vergrößern in jedem Fall den Aufwand, den ein Angreifer treiben muss, um Spielstände manipulieren zu können.
|
+
| (9/1)
+
| 8
+
| 7
+
| 1
+
| 16
+
|
+
|
+
+
  
|-
+
Unabhängig vom gewählten Dateiformat sollte grundsätzlich immer eine ''Versionsnummer'' mitgespeichert werden. Dies erleichtert es, Änderungen am Dateiformat durchzuführen (z. B. nach einem Spiel-Update) und veraltete Dateien zu erkennen und ggf. gesondert zu behandeln.
|}
+
 
Wenn man jetzt vom Zielknoten zurückgeht über Comefrom kommt man automatisch zum Startknoten. <br/>
+
=== XML ===
(2/2) -> (2/3) -> (2/4) -> (2/5) -> (2/6) -> (2/7) -> (3/7) -> (4/7) -> (5/7) -> (6/7) -> (7/7) -> (8/7) -> (9/7) -> (10/7) <br/>
+
 
 +
Bei der [http://de.wikipedia.org/wiki/Extensible_Markup_Language Extensible Markup Language] handelt es sich um eine standardisierte und weit verbreitete Auszeichnungssprache. Sie besteht aus Elementen, die durch Tags gekennzeichnet werden, Attribute, Text und weitere Elemente enthalten können. Mit Hilfe einer [http://de.wikipedia.org/wiki/Schemasprache Schemasprache] wie [http://de.wikipedia.org/wiki/XML_Schema XML Schema], welches ebenfalls in Form einer XML-Datei vorliegt, kann überprüft werden, ob eine XML-Datei den korrekten Aufbau besitzt und somit valide ist.
 +
 
 +
==== Datenstruktur ====
 +
 
 +
Dadurch, dass eine XML-Datei aus einem Root-Element besteht und jedes Element beliebig viele weitere Elemente enthalten kann, sind die Daten in einer XML-Datei hirarchisch angeordnet. ''m:n''-Beziehungen lassen sich somit nicht direkt einbetten, sondern nur über die Verwendung speziellen Werten, die entsprechende Elemente identifizieren. Es gibt aber keine automatische Prüfung, ob ein referenziertes Element tatsächlich vorhanden ist.
 +
 
 +
==== Manipulierbarkeit ====
 +
 
 +
Da es sich bei XML um ein textuelles, weit verbreitetes Format handelt, kann man davon ausgehen, dass es nicht besonders schwer ist, Dateien dieses Typs zu bearbeiten.
 +
 
 +
==== Vorteile ====
 +
 
 +
Der größte Vorteil von XML ist dessen weite Verbreitung. Diese hat zur Folge, dass es bereits viele Programme zum Bearbeiten von XML-Dateien und Bibliotheken zum Arbeiten mit XML-Dateien gibt. Zudem unterstützen viele Editoren auch das Überprüfen der XML-Dateien anhand einer Schemadatei. Dadurch ist sowohl das Arbeiten mit XML-Dateien für die Spieleentwickler, als auch das nachträgliche Editieren durch die Benutzer einfach möglich, und das mit dem richtigen Programm auch ohne große Kenntnisse über dieses Datenformat.
 +
 
 +
XML-Dateien eignen sich besonders gut, wenn dessen Inhalt später nicht nur von dem Spiel selbst bearbeitet werden soll.
 +
 
 +
==== Nachteile ====
 +
 
 +
XML-Dateien enthalten im Allgemeinen viel Redundanz und Overhead und benötigen daher viel Speicherplatz. Daher ist es üblich, XML-Dateien zu komprimieren oder auf eine binäre Variante auszuweichen [http://de.wikipedia.org/wiki/Binary_XML]. Dadurch gehen die Vorteile von XML jedoch zu einem gewissen Grad wieder verloren.
 +
 
 +
===XDS===
 +
XDS basiert auf XML, ist im Unterschied dazu allerdings binär und eignet sich so in für eine sicherere Speicherung von Spieldaten. Es ist für kleine Dateigrößen und schnelle Auslesezeiten optimiert und verbindet somit die Vorteile von XML mit denen von Binären Formaten. Genaueres dazu in Game Programming Gems 4.
 +
 
 +
=== YAML ===
 +
 
 +
[http://de.wikipedia.org/wiki/YAML YAML] ist eine vereinfachte Auszeichnungssprache, also eine Auszeichnungssprache mit vereinfachter Syntax, die ehemals von [[#XML|XML]] abgeleitet war und geringfügig mit XML vergleichbar ist. Der Zweck von YAML ist die Serialisierung von Daten.
 +
 
 +
==== Datenstruktur ====
 +
 
 +
YAML verwendet Skalare (Einzelwerte), Listen und assoziative Listen als Datenstrukturen. Diese können hirarchisch angeordnet werdne. ''m:n''-Beziehungen lassen sich nicht direkt, sondern nur über Verwendung von bestimmten Werten zur Identifizierung anderer Daten realisieren. Es gibt allerdings keine automatische Prüfung, ob referenzierte Daten tatsächlich vorhanden sind.
 +
 
 +
==== Manipulierbarkeit ====
 +
 
 +
YAML ist ein im Gegensatz zu XML weniger stark verbreitetes, textuelles Format. Im Gegensatz zu XML dürfte die Zeitspanne bis zur Analyse der Datenstrukturen etwas, aber nur geringfügig, größer sein.
 +
 
 +
=== CSV ===
 +
 
 +
Das Dateiformat [http://de.wikipedia.org/wiki/CSV_(Dateiformat) CSV] ist ein einfaches textuelles Format. Dieses Format ist zwar nicht standardisiert, allerdings beschreibt die [http://tools.ietf.org/html/rfc4180 RFC 4180] den grundlegenden Aufbau. In der Praxis werden statt der Kommas teilweise Semikoli verwendet. Zugunsten der Plattformunabhängigkeit kann für ein Projekt festgelegt werden, dass als Zeilenumbruch sowohl die Steuerzeichen ''Carriage Return'', als auch das Steuerzeichen ''Line Feed'', als auch die Kombination ''Carriage Return'' mit folgendem ''Line Feed'' gültig sind.
 +
 
 +
==== Datenstruktur ====
 +
 
 +
Wenn man der Empfehlung folgt, alle Zeilen einer CSV-Datei mit der gleichen Anzahl an Daten zu befüllen, dann werden die Daten tabellarisch angeordnet. Die 1. Zeile kann gegebenenfalls als Titel der spalten interpretiert werden, wobei diese auch aus dem Zusammenhang der Datei erkannt werden kann. Das Format an sich bietet nicht die Möglichkeit, Abhängigkeiten der Daten darzustellen. Wie bei anderen Formaten kann ein Datensatz, also eine Zeile, durch einen Wert eindeutig identifiziert und referenziert werden. Es gibt keine Mechanismen, die sicherstellen, dass ein so referenzierter Datensatz auch tatsächlich vorhanden ist.
 +
 
 +
==== Vorteile ====
 +
 
 +
Bei dem Dateiformat handelt es sich um ein sehr einfaches Format. Wenn die Empfehlung, nur gleich lange Datensätze einzufügen, eingehalten wird, können damit tabellarische Daten gut abgespeichert werden. Beispielsweise könnten in einer CSV-Datei das Level eines Charakters und dazu die entsprechenden Fertigkeitswerte, wie Stärke, Intelligenz oder Geschick, gespeichert werden.
 +
 
 +
Zudem kann es bedingt in andere textuelle und teilweise in binäre Formate eingebettet werden. Ein Beispiel für ein textuelles Format wäre XML, bei dem die Elemente fast beliebigen Text enthalten können und ein Beispiel für ein binäres Format wäre eine Datenbank. Auch wenn es möglich ist, sollte man in der Praxis davon abstand nehmen, Daten im CSV Format in einer Datenbank zu speichern, da dies ein Hinweis für eine schlechte Normalisierung wäre. Bei anderen Formaten stellen diese Formate selbst in der Regel entsprechende Konstrukte bereit, mit denen die Daten gespeichert werden können. Somit sollte eine Einbettung eine Ausnahmesituation darstellen.
 +
 
 +
=== Datenbank ===
 +
 
 +
Auch eine Datenbank kann dazu verwendet werden, gespeicherte Spielstände zu verwalten. Dabei können Features von Datenbankmanagementsystemen genutzt werden, um das Laden und Speichern effizient oder besonders robust zu gestalten.
 +
 
 +
==== Manipulierbarkeit ====
 +
 
 +
Da es sich bei Datenbanken um binäre Dateien handelt, sind diese grundsätzlich nur schwer mit Text-/Hexeditoren zu bearbeiten. Allerdings ist es relativ unproblematisch mit dem verwendeten eingebetteten DBMS auf die Datei zuzugreifen und diese zu verändern. Da solche Datenbanksysteme meist keine Benutzerverwaltung verfügen, kann vor einem solchen Zugriff kein Schutz eingerichtet werden.
 +
 
 +
=== Eigenes binäres Format ===
 +
 
 +
Ein eigenes binäres Format folgt keinem Dateiformatstandard.
 +
 
 +
==== Manipulierbarkeit ====
 +
 
 +
Da eigene binäre Formate nicht verbreitet sind, stellen diese grundsätzlich den besten Schutz gegen Manipulationen dar. Allerdings sollte man sich vor Augen halten, dass auch dieses Format analysiert werden kann und dadurch der Schutz nach einer gewissen Zeit nicht mehr zwingend gegeben ist.
 +
 
 +
== Version des Spielstandes ==
 +
Im laufe der Zeit kommt es vor, dass ein Spiel abgeändert wird. Ein Update um die Grafik zu verbessern oder um einen Bug zu fixen oder aber eine Änderung der Lade- und Speicherfunktion für die Spielstände. Dies kann bedeuten das mehr oder weniger Informationen in dem Spielstand gespeichert werden müssen. Für solche Fälle ist es angebracht in dem Spielstand eine Versionnummer zu speichern. Eine Versionsnummer kann verhindern das ältere Spielstände geladen werden und möglicherweise Probleme verusachen.
 +
 
 +
Aus der Sicht des Spieler ist es natürlich frustrierend ein Spiel wieder neu anfangen zu müssen, weil der Spielstand nicht mehr geladen wird. Diesem Problem kann der Programmierer leicht entgegenwirken. Eine Möglichkeit ist es, die Versionsnummer des Spielstandes zu ermitteln und für jede Version eine Angepasste Laderoutine zu implementieren. Eine andere herangehensweis an das Problem kann sein, einen Spielstandkonverter zu schreiben und so den alten Spielstand der neuen Ladefunktion anzupassen.
 +
 
 +
== Quellen zum Durchlesen ==
 +
* http://www.spieleprogrammierer.de/18-c-cplusplus-csharp-delphi-java-python-und-lua/10381-laufzeitdaten-speichern-spielstände/
 +
* http://www.ludism.org/gamedesign/SaveGamePatterns
 +
* http://csweb.ucc.ie/~dongen/cs2500/10-11/41/Notes.pdf

Aktuelle Version vom 11. September 2012, 18:19 Uhr

Klicke hier, um diese Version anzusehen.

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge