Eine Funktion, die in fast jedem größeren Spiel benötigt wird, ist das Speichern von Spielständen und benutzerbezogenen Daten. Dieses Beispiel soll zeigen, wie mit Hilfe von Listen und Objekten eine flexible Spielstandspeicherung umgesetzt werden kann.
Das Objekt SpielstandObjekt speichert den aktuellen Spielstand in eine angegebene Datei. Objekte, die Werte speichern und laden wollen, melden sich beim Spielstandobjekt an. Dazu müssen sie Methoden definieren. Die Spielstandsspeicherung funktioniert in 2 Schritten: Bei der Konstruktion des Objektes wird die angegebene Datei eingelesen und interpretiert. Danach erhält man mit der Methode getUserList() eine Liste der Benutzernamen, die einen Spielstand gespeichert haben. Mit Hilfe des Benutzernamens lässt sich ein Spielstand laden und speichern; außerdem ist es möglich, den Dateinamen des Spielstandes zu ändern, um ihn unter einem anderen Namen zu speichern. Wichtig ist, dass sich das FileIO-Xtra im Xtras-Ordner des Projektors befindet, da es zum Lesen und Schreiben von Dateien benötigt wird.
Bemerkung
In einer Shockwave-Anwendung funktioniert das Lesen und Schreiben von Dateien
mit FileIO nicht. Soll der Spielstand dennoch lokal gespeichert werden, ist
das Objekt so anzupassen, dass mit den Befehlen getPref()
und setPref() der Spielstand in den Voreinstellungen
gespeichert und geladen wird. Eine entsprechende Version findet sich im Beispiel-Film.
Das SpielstandObjekt macht von zwei praktischen Lingo-Funktionen Gebrauch: string() und value(). Mit string() kann eine Liste in eine Zeichenkette umgewandelt werden. Value() ist die Umkehrfunktion und generiert aus der Zeichenkette wieder eine Liste.8
Methoden des Objekts SpielstandObjekt
new
on new me, fileName
Erzeugt ein neues Spielstand-Objekt, dass die Daten aus der Datei fileName einliest; wenn sie nicht existiert, wird eine neue Datei erzeugt.
Achtung: Der Dateiname muss unbedingt als absoluter Pfad eingegeben werden!Parameter:
fileName - der Dateiname der Spielstandsdatei mit absolutem PfadRückgabewert:
Gibt eine Referenz auf das Spielstandsobjekt zurück. Wenn die angegebene Datei nicht gelesen werden konnte, wird 0 zurückgegeben.
register
on register me, scoreObjekt
Registriert ein Objekt, das Werte in den Spielstand speichern bzw. Werte aus dem Spielstand auslesen soll. Das Objekt muss die Methoden die Methoden scoreSymbol(), toScoreString() und fromScoreString() implementieren (s.u.).
Parameter:
scoreObjekt - Das Objekt, das Werte laden und speichern soll.
loadScore
on loadScore me, aUserName
Lädt den Spielstand eines Benutzers und aktualisiert die angemeldeten Objekte. Existiert der Benutzer noch nicht, wird er neu angelegt.
Parameter:
aUserName - Name des Benutzers, dessen Spielstand geladen werden soll.Rückgabewert:
TRUE, wenn das Laden erfolgreich war, FALSE, wenn ein Fehler beim Laden auftrat.
saveScore
on saveScore me, aUserName
Speichert den Spielstand der angemeldeten Objekte unter dem angegebenen Benutzernamen.
Parameter:
aUserName - Benutzername, unter dem gespeichert wird.Rückgabewert:
TRUE, wenn das Speichern erfolgreich war, FALSE, wenn ein Fehler beim Speichern auftrat.
changeFilename
on changeFilename me, aFileName
Ändert den Dateinamen, unter dem der Spielstand gespeichert wird.
Parameter:
aFileName - Der neue Dateiname mit absoluter Pfadangabe.
getUserList
on getUserList me
Gibt eine Liste mit allen Benutzernamen zurück, die Spielstände gespeichert haben.
Rückgabewert:
Gibt eine lineare Liste zurück, die die Benutzernamen enthält.
Methoden der angemeldeten Objekte
Objekte, die mit Hilfe des SpielstandObjektes
laden und speichern wollen, müssen folgende Methoden implementieren:
scoreSymbol
on scoreSymbol me
Gibt ein eindeutiges Symbol zurück, an Hand dessen das Objekt beim Laden identifiziert wird.
Rückgabewert:
Ein für jedes Objekt eindeutiges Symbol.
toScoreString
on toScoreString me
Gibt die zu speichernden Werte in Form einer Zeichenkette zurück. Die Zeichenkette sollte eine Form haben, aus der hinterher leicht wieder die gespeicherten Werte zu rekonstruieren sind, beispielsweise eine mit string() konvertierte Liste.
Rückgabewert:
Ein String, der die zu speichernden Werte enthält.
fromScoreString
on fromScoreString me, aString
Rekonstruiert aus einer geladenen Zeichenkette die gespeicherten Werte. Wenn die Zeichenkette beispielsweise eine konvertierte Liste ist, kann die Liste mit value() wieder zurückgewandelt werden. Wurde noch kein Wert gespeichert, wird der Wert EMPTY, also eine leere Zeichenkette übergeben.
Parameter:
aString - Die Zeichenkette, die mit toScoreString() gespeichert wurde oder EMPTY.
Das Objekt InventarObjekt ist ein Beispiel für
ein solches Objekt:
-- speichert gefundene Gegenstände
property mFoundItemsList
on new me
-- Liste mit gefundenen Gegenständen
mFoundItemsList = []
return me
end new
on addItem me, anItem
-- fügt einen Gegenstand hinzu
mFoundItemsList.add(anItem)
end addItem
on checkItem me, anItem
-- prüft, ob ein Gegenstand vorhanden ist
return (mFoundItemsList.getPos() <> 0)
end checkItem
on removeItem me, anItem
-- entfernt einen Gegenstand
mFoundItemsList.deleteOne(anItem)
end removeItem
-- Skripte, die für die Spielstandsspeicherung wichtig sind
on scoreSymbol me
return #inventar
end scoreSymbol
on toScoreString me
return string(mFoundItemsList)
end toScoreString
on fromScoreString me, aString
if aString = EMPTY then
mFoundItemsList = []
else
mFoundItemsList = value(aString)
end if
end fromScoreString
Das Objekt dient dazu, gefundene Gegenstände in einem Spiel zu speichern. Es kann geprüft werden, ob ein Gegenstand schon gefunden wurde und dieser auch wieder aus dem Inventar entfernt werden. Die folgenden Zeilen erzeugen ein Inventarobjekt und fügen den gefundenen Gegenstand "Landkarte" hinzu:
rucksackObj = script("InventarObj").new()
rucksackObj.addItem(#landkarte)
Folgende Zeilen speichern das Objekt in der Datei "spielstand.txt" im aktuellen Verzeichnis unter dem Benutzernamen "Otto":
dateiName = the moviePath & "spielstand.txt"
scoreObj = script("SpielstandObjekt").new(dateiName)
scoreObj.register(rucksackObj)
scoreObj.loadScore("Otto")
Anschließend lässt sich der Spielstand von "Heide" mit folgender Zeile laden:
scoreObj.loadScore("Heide")
Es lassen sich beliebig viele Objekte an einem Spielstand-Objekt anmelden. Hier ist der komplette Lingo-Code.
-- dieses Objekt kümmert sich um die automatische
Speicherung des
-- Spielstandes nach Benutzernamen; Objekte, deren Zustand gespeichert werden
soll,
-- melden sich mit der Methode "register" an; sie müssen drei
-- Methoden implementieren:
--
-- scoreSymbol:
-- gibt ein eindeutiges Symbol zurück, dass diesen Spielstand
-- in der gespeicherten Liste beschreibt, z.B. #inventar für
-- ein Objekt, das speichert, welche Gegenstände eingesammelt wurden
--
-- toScoreString:
-- gibt die Eigenschaften des Objekts als Zeichenkette zurück
--
-- fromScoreString:
-- stellt den Zustand des Objektes aus einer Zeichenkette wieder her
-- eine leere Zeichenkette bedeutet neuer Benutzer
--
-- der Spielstand wird mit Hilfe des Xtras FileIO gespeichert; es
-- muss sich im Xtras-Ordner befinden
property mFileName, mObjectList, mScoreList
property FILEIO_READ_AND_WRITE, FILEIO_READ, FILEIO_WRITE
on new me, aFileName
-- erzeugt ein neues Spielstand-Objekt, das die Daten
-- aus der Datei aFileName einliest; gibt 0 zurück, wenn
-- der Spielstand nicht eingelesen werden konnte; wenn keine
-- Datei existiert wird versucht, eine zu erzeugen
-- ACHTUNG: Der Dateinamen muss absolut sein!
-- Dateinamen der Datei, die den Spielstand enthält
mFileName = aFileName
-- Liste mit zu speichernden/ladenden Objekten
mObjectList = [:]
-- Konstanten, um das lesen des Skriptes übersichtlicher zu machen
FILEIO_READ_AND_WRITE = 0
FILEIO_READ = 1
FILEIO_WRITE = 2
-- Liste, die alle Spielstände enthält
mScoreList = [:]
-- öffnen der Spielstandsdatei und laden aller Spielstände
myFile = xtra("fileio").new()
if not objectP(myFile) then
put "FileIO nicht gefunden!"
return 0
end if
myFile.openFile(mFileName, FILEIO_READ)
if myFile.status() <> 0 then
-- Datei existiert nicht: Datei erzeugen
myFile.createFile(mFileName)
if myFile.status() <> 0 then
-- konnte Datei nicht erzeugen
put "Datei konnte nicht erzeugt werden:"
&& myFile.error(myFile.status())
myFile = 0
return 0
end if
-- Datei erfolgreich erzeugt
myFile = 0
else
-- Datei erfolgreich geöffnet: Daten einlesen
fileData = myFile.readFile()
if fileData = EMPTY then
mScoreList = [:]
else
mScoreList = value(fileData)
end if
myFile.closeFile()
myFile = 0
end if
return me
end new
on register me, obj
-- meldet des Objekt obj als zu speicherndes Objekt beim Spielstand an
-- es muss die Methoden scoreSymbol, toScoreString und fromScoreString
-- implementieren
mObjectList.setAProp(obj.scoreSymbol(), obj)
end register
on loadScore me, aUserName
-- lädt den Spielstand des Benutzers aUserName; gibt TRUE zurück,
wenn
-- das Laden erfolgreich war, FALSE wenn es nicht möglich war zu laden
-- wenn der Name nicht existiert, wird er erzeugt
userScore = mScoreList.getAProp(aUserName)
if voidP(userScore) then
-- neuer Benutzer: für jedes Objekt eine leere Zeichenkette eintragen
userScore = [:]
repeat with objNum = 1 to mObjectList.count()
userScore.setAProp(mObjectList.getPropAt(objNum), EMPTY)
end repeat
end if
-- alle angemeldeten Objekte initialisieren
repeat with objNum = 1 to userScore.count()
obj = mObjectList.getAProp(userScore.getPropAt(objNum))
if voidP(obj) then
-- Objekt nicht angemeldet
put "Objekt" && QUOTE & userScore.getPropAt(objNum)
& QUOTE && "ist nicht angemeldet!"
return FALSE
end if
-- Objekt initialisieren
obj.fromScoreString(userScore[objNum])
end repeat
return TRUE
end loadScore
on saveScore me, aUserName
-- speichert den Spielstand des Benutzers aUserName; gibt TRUE zurück,
-- wenn das Speichern erfolgreich war, FALSE wenn es nicht möglich war
-- zu speichern
userScore = [:]
repeat with obj in mObjectList
userScore.setAProp(obj.scoreSymbol(), obj.toScoreString())
end repeat
mScoreList.setAProp(aUserName, userScore)
-- Datei öffnen und speichern
myFile = xtra("fileio").new()
if not objectP(myFile) then
put "FileIO nicht gefunden!"
return 0
end if
myFile.openFile(mFileName, FILEIO_WRITE)
if myFile.status() <> 0 then
-- Datei kann nicht geöffnet werden
put "Datei kann nicht geöffnet werden." &&
myFile.error(myFile.status())
return FALSE
end if
myFile.delete()
if myFile.status() <> 0 then
-- Datei kann nicht gelöscht werden werden
put "Datei kann nicht überschrieben werden." &&
myFile.error(myFile.status())
return FALSE
end if
myFile.createFile(mFileName)
myFile.openFile(mFileName, FILEIO_WRITE)
myFile.writeString(string(mScoreList))
myFile.closeFile()
myFile = 0
return TRUE
end saveScore
on changeFilename me, aFileName
-- ändert den Dateinamen, unter dem gespeichert wird
mFileName = aFileName
end changeFilename
on getUserList me
userList = []
-- gibt eine Liste mit allen Benutzernamen zurück
repeat with user = 1 to mScoreList.count()
userList.add(mScoreList.getPropAt(user))
end repeat
return userList
end getUserList
![]() |
|||
![]() |
4.6 Analogien und Unterschiede zwischen Listen und Skript-Objekten | 4.8 Statische Objekte und Instanzen | ![]() |