Skyrim:State

Aus Skript-Wiki
Wechseln zu: Navigation, Suche

Überblick

Scripts laufen in verschiedenen States (Zuständen) – aber ein Script kann nur in einem zur Zeit sein. Welcher Code beim Aufruf einer Funktion abläuft oder welches Event eintritt hängt vom State ab, in dem das Script sich befindet.

Definitieren eines States

Das Definieren eines States in einem Script ist sehr einfach. Setze einfach einen State-Block wie folgt:

<papyrusscript> state MyState

 ; hier sind verschiedene Funktionen

endState </papyrusscript>

Wenn man sein Script in einem bestimmten State starten will, füge vor dem State-Block ein "auto" hinzu: <papyrusscript> auto state StartHere

hier sind verschiedene Funktionen

endState </papyrusscript>

Der 'Empty State'

Der 'Empty State' ist ein impliziter State, der alle Funktionen, die sich nicht in einem State-Block befinden, enthält:

<papyrusscript> function MyFunction()

 ; Diese Funktion ist im  'Empty State'

endFunction

state MyState

 function MyFunction()
Diese Funktion ist im ‚MyState‘ State
 endFunction

endState </papyrusscript>

Definieren von Funktionen/Events innerhalb von States

Um eine Funktion oder ein Event innerhalb eines States zu definieren, genügt es, einfach die Funktion oder das Event innerhalb des State-Blocks zu verwenden. <papyrusscript> state MyState

 function SpecialFunction()
   ; Diese  Funktion ist innerhalb des MyState-States
 endFunction

endState </papyrusscript>

Bitte beachte: die Funktion oder das Event muss im 'Empty State' mit dem selben Return-Typ und den selben Parametertypen definiert sein, sonst wird der Compiler sich beschweren. Dies ist wegen der Art, wie das Spiel Funktions- und Event-Aufrufe zur Laufzeit realisiert.

<papyrusscript> function SampleFunction(int myParameter)

 ; Code here

endFunction

state SampleState

 function SampleFunction(int aParameter)
   ; diese Funktion ist in Ordnung – der Parametertyp des Parameters ist der selbe wie im 'Empty State'
 endFunction
 function OtherFunction()
   ; Error! OtherFunction existiert nicht im  'Empty State'
 endFunction

endState

state OtherState

 int function SampleFunction(int myParameter)
   ; Error! Der Return-Typ von SampleFunction passt nicht zu dem im 'Empty State'
 endFunction

endState

state YetAnotherState

 function SampleFunction(int myParameter, float parameter2)
   ; Error! Die Parameter von SampleFunction passen nicht zu denen im 'Empty State'
 endFunction

endState </papyrusscript>

Der Einfachheit halber sind Events, die von verschienenen Arten von Scripts empfangen werden können, schon in den Empty States innerhalb der Scripts definert, die man erweitern will (d.h. ObjectReference, Actor usw.) . Deshalb ist es auch nicht nötig, Events im Empty State zu defineren, wenn alles was man möchte, eine Modifikation des Events in einem einzelnen Fall ist.


Wie Funktionen ausgewählt werden

Wenn eine Funktion aufgerufen wird, oder das Objekt ein Event empfängt, findet die Auswahl wie folgt statt:

  1. Wenn das Script die Funktion im derzeitigen State hat, wird diese aufgerufen
  2. Wenn das Script ein anderes Script laufen hat, das die Funktion in dessen derzeitigen State hat, wird diese aufgerufen
  3. Wenn das Script die Funktion im 'Empty State' hat, wird diese aufgerufen
  4. Wenn das Script ein anderes Script laufen hat, das die Funktion in dessen 'Empty State' hat, wird diese aufgerufen

In Kurzfassung: Funktionen innerhalb von States übersteuern Funktionen innerhalb des 'Empty States' und Funktionen innerhalb eines Scripts übersteuern diejenigen in den von ihm aufgerufenen Scripts.

Wie der State eines Scripts gesetzt wird

Das Setzen des States eines Scripts ist einfach. Man muss nur GotoState(string asStateName) mit dem Namen des States, der gesetzt werden soll, als String. Der folgende Ablauf von Events wird dann stattfinden.

  1. OnEndState wird für den State an das Script gesandt, der vorher gerade da war.
  2. Der State wird auf den angefragten State geändert
  3. OnBeginState wird für den State an das Script gesandt, in den man gerade eingetreten ist.

Der Name des States, in den man eintreten will, ist nicht abhängig von Groß- und Kleinschreibung. Wenn man in den 'Empty State' eintreten will, reicht es als Namen den Leerstring "" anzugeben. Außerdem beendet der Aufruf GotoState die Funktion nicht. sie läuft noch weiter. Es ist gänzlich zulässig, den State des Objektes nur für die Dauer eines kleinen Stückchens Quellcode zu ändern und zurück zu ändern wenn das erledigt ist.

<papyrusscript> function MyFunction()

 GotoState("TurnOffActivate")
 ; Hier wird ein Haufen langwieriges Zeugs gemacht
 GotoState("")

endFunction

state TurnOffActivate

 event OnActivate(ObjectReference akTriggerRef)
   ; mache nichts
 endEvent

endState </papyrusscript>

Wie man den State eines Scripts erhält

Es ist ebenfalls einfach, den State eines Scripts zu erhalten. Der Aufruf [GetState - All Scripts|GetState]]() gibt den Namen des States als String zurück, in dem sich das Script gerade befindet. Es ist zu beachten, dass der Groß- und Kleinschreibung des Namens des States vom Aufruf abhängt, der die Groß- und Kleinschreibung an der ersten Stelle setzt und dass String-Vergleiche case-sensitive (also abhängig von Groß- und Kleinschreibung) sind. Man muss beim Stringvergleich also aufpassen. (In Zukunft wird es Wege geben, um beim Stringvergleich Groß- und Kleinschreibung zu ignorieren – bis dahin muss man vorsichtig sein)

Tricks und Tipps

  • Wenn man ein Event oder eine Funktion abschalten will, während man in einem bestimmten State ist, muss man nur das Event oder die Funktion im State definieren und leer lassen. Dies ist besonders nützlich, wenn man jedes aktivierter Event, sagen wir mal, ignorieren möchte, solange man mitten in einer Tätigkeit ist.
  • Wenn es zu einschränkend ist, nur einen State zur Zeit zu haben, erinnere man sich daran, dass man mehrfache Scripts an das selbe Objekt hängen kann – und jedes Script seinen eigenen separaten State haben kann. Das mag helfen, wenn man etwas komplexere Operationen hat. Natürlich kann man auch auf den Gebrauch von If-Statements zurück fallen ebenso mit den eigenen State-Variablen.
  • Weil State-Namen einfach Strings sind, kann man sie zur Laufzeit mit dem "+" Operator erstellen. Zum Beispiel kann man "State1", "State2" usw. erstellen und sie dann mit dem Folgenden auswählen:

<papyrusscript> Function GotoNumberedState(int number)

 GotoState("State" + number)

EndFunction </papyrusscript>

<papyrusscript> Function GotoNumberedState(int number)

 GotoState("State" + number)

EndFunction </papyrusscript>

Folgerung

States sind mächtige halbwegs einfache Wege, um das Verhalten eines Scripts zu ändern ohne übermäßig umfangreiche If-Statements oder anderen komplizierten Code zu schreiben. Manchmal ist es so, dass Probleme, die übermäßig komlex oder beschwerlich aussehen, einfacher werden, wenn man States kreativ nutzt

Siehe auch