Skyrim:State Reference: Unterschied zwischen den Versionen

Aus Skript-Wiki
Wechseln zu: Navigation, Suche
K (Die Seite wurde neu angelegt: =Ü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 o...)
 
K (Textersetzung - „tesscript>“ durch „papyrusscript>“)
 
(3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
=Überblick=
+
Ein "State" ist ein Modus, in den sich  ein Script befinden kann, was zu verschieden aufrufbaren Versionen von [[sk:Function Reference|Funktionen]] oder [[sk:Events Reference|Events]] führt.
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=
+
== State Definition ==
Das Definieren eines States in einem Script ist sehr einfach. Setze einfach einen State-Block wie folgt:
+
<state> ::= ['Auto'] 'State' <identifier>
 +
              <function or event>*
 +
            'EndState'
  
<tesscript>
+
Ein State wird definiert, indem das [[sk:Keyword Reference|Keyword]] "State" angegeben wird (mit optional vorangestelltem "Auto") gefolgt vom [[sk:Identifier Reference|Identifier]], der den State repräsentiert. Er enthält keine oder mehr Funktionen oder Events und endet mit dem Keyword "EndState".
state MyState
 
  ; hier sind verschiedene Funktionen
 
endState
 
</tesscript>
 
  
Wenn man sein Script in einem bestimmten State starten will, füge vor dem State-Block ein "auto"  hinzu:
+
== Auto-State ==
<tesscript>
+
Wenn einem State ein "Auto" voran gestellt ist, startet das Script in diesem State (und es wird kein [[sk:OnBeginState|OnBeginState]]  gesendet. Es kann nur einen Auto State in einem Script geben.  Wenn ein Child-Script einen Auto-State hat, hat dieser Vorrang über den das Parents, wenn das Child-Script jedoch keinen hat, wird der des Parents genutzt.
auto state StartHere
 
; hier sind verschiedene Funktionen
 
endState
 
</tesscript>
 
  
==Der 'Empty State'==
+
== Der 'Empty State' ==
Der 'Empty State' ist ein impliziter State, der alle Funktionen, die sich nicht in einem State-Block befinden, enthält:
+
Alle Funktionen oder Events, die außerhalb eines State-Blocks definiert wurden, werden einem 'Empty State' zugerechnet. Dies ist ebenso, wenn eine Funktion genutzt wird, wenn das Script nicht in irgendeinem State ist, oder wenn derzeitige State keine Funktion implementiert oder übersteuert. Jede in einem State implementierte Funktion muss auch im 'Empty State' (mit identischem Namen, Return-Typen und Parameterliste) implementiert werden und zwar im aktuellen Script oder einem Parent.
  
<tesscript>
+
== Wechseln von States ==
function MyFunction()
+
Um einen State in einem Script zu wechseln, ruft man [[sk:GotoState|GotoState]] auf und übergibt den Namen des States, zu dem man wechseln will, als String. Der State muss in dem aufgerufenen Script nicht existieren. Um in den 'Empty State' zu wechseln, wird  ein leerer String übergeben.
  ; Diese Funktion ist im 'Empty State'
+
.
endFunction
 
  
state MyState
+
== Abfrage des derzeitigen States ==
  function MyFunction()
+
Um den derzeitigen State zu erhalten, ruft man [[sk:GetState|GetState]] auf. Es wird der Name der aktuellen States als String zurück gegeben.
; Diese Funktion ist im ‚MyState‘ State
 
  endFunction
 
endState
 
</tesscript>
 
  
=Definieren von Funktionen/Events innerhalb von States=
+
== Wie ein State sich auf Funktionen und Events auswirkt==
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.
+
Die zum Laufen ausgewählte Funktion oder das Event wird durch folgenden Algorithmus bestimmt:
<tesscript>
+
*Überprüft den State des aktuellen Scripts auf die Funktion
state MyState
+
*Überprüft den State des Parent-Scripts auf die Funktion
  function SpecialFunction()
+
*Überprüft den 'Empty State' des aktuellen Scripts auf die Funktion
    ; Diese  Funktion ist innerhalb des MyState-States
+
*Überprüft den 'Empty State' des Parent-Scripts auf die Funktion
  endFunction
 
endState
 
</tesscript>
 
  
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.
+
== Beispiele==
 
+
<papyrusscript>
<tesscript>
+
; Definiert eine Funktion und einen State mit Übersteuerung
function SampleFunction(int myParameter)
+
a function and a state with an override
  ; Code here
+
int Function MyFunction()
endFunction
+
  Return 1
 
+
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
 
</tesscript>
 
  
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.  
+
State MyState
 +
  int Function MyFunction() ; Name, Parameter und Type des Returns müssen der Version
 +
                            ;im 'Empty State' entsprechen.  
 +
    Return 2
 +
  EndFunction
 +
EndState
  
 
+
Function CallMyFunction()
 
+
  int x = MyFunction() ; Zuweisung von 1, wenn das Script das erste mal läuft ( in keinem State)
=Wie Funktionen ausgewählt werden=
+
  GotoState("MyState")
Wenn eine Funktion aufgerufen wird, oder das Objekt ein Event empfängt, findet die Auswahl wie folgt statt:
+
  x = MyFunction() ; Zuweisung von 2
 
+
  GotoState("WrongState")
# Wenn das Script die Funktion im derzeitigen State hat, wird diese aufgerufen
+
  x = MyFunction() ; Zuweisung von 1 (Rückfall, weil State in diesem Script nicht existiert,
# Wenn das Script ein anderes Script laufen hat, das die Funktion in dessen derzeitigen State hat, wird diese aufgerufen
+
                  ; aber in einem Child–Script existieren könnte)
# Wenn das Script die Funktion im 'Empty State' hat, wird diese aufgerufen
+
fallback because state doesn't exist in this script, but might in a child)
# 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 übersteueren 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 - All Scripts|GotoState]](string asStateName) mit dem Namen des States, der gesetzt werden soll, als String. Der folgende  Ablauf von Events wird dann stattfinden.
 
#[[sk:OnEndState| OnEndState]] wird für den State an das Script gesandt, der vorher gerade da war.
 
#Der State wird auf den angefragten State geändert
 
#[[sk:OnBeginState| 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 - All Scripts|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.
 
 
 
<tesscript>
 
function MyFunction()
 
  GotoState("TurnOffActivate")
 
  ; Hier wird ein Haufen langwieriges Zeugs gemacht
 
 
   GotoState("")
 
   GotoState("")
endFunction
+
  x = MyFunction() ; Zuweisung von  1 ('Empty State')
 +
EndFunction
 +
</tesscript >
 +
<br>
 +
<papyrusscript>
 +
; Ändern des States im obigen Beispiel in ein Auto-State.
 +
Auto State MyState
 +
  int Function MyFunction() ; Name, Parameter und Type des Returns müssen der Version
 +
                            , im 'Empty State' entsprechen.
  
state TurnOffActivate
+
     Return 2
  event OnActivate(ObjectReference akTriggerRef)
+
   EndFunction
     ; mache nichts
+
EndState
   endEvent
 
endState
 
</tesscript>
 
  
=Wie man den State eines Scripts erhält=
+
; Nun wird  x in CallMyFunction() 2, 2, 1, 1 zugewiesen, weil das Script mit MyState beginnt.
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)
+
</papyrusscript>
 
 
=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:
 
 
 
<tesscript>
 
Function GotoNumberedState(int number)
 
  GotoState("State" + number)
 
EndFunction
 
</tesscript>
 
 
 
<tesscript>
 
Function GotoNumberedState(int number)
 
  GotoState("State" + number)
 
EndFunction
 
</tesscript>
 
  
=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==
 
==Siehe auch==

Aktuelle Version vom 13. August 2012, 12:00 Uhr

Ein "State" ist ein Modus, in den sich ein Script befinden kann, was zu verschieden aufrufbaren Versionen von Funktionen oder Events führt.

State Definition

<state> ::= ['Auto'] 'State' <identifier>
              <function or event>*
            'EndState'

Ein State wird definiert, indem das Keyword "State" angegeben wird (mit optional vorangestelltem "Auto") gefolgt vom Identifier, der den State repräsentiert. Er enthält keine oder mehr Funktionen oder Events und endet mit dem Keyword "EndState".

Auto-State

Wenn einem State ein "Auto" voran gestellt ist, startet das Script in diesem State (und es wird kein OnBeginState gesendet. Es kann nur einen Auto State in einem Script geben. Wenn ein Child-Script einen Auto-State hat, hat dieser Vorrang über den das Parents, wenn das Child-Script jedoch keinen hat, wird der des Parents genutzt.

Der 'Empty State'

Alle Funktionen oder Events, die außerhalb eines State-Blocks definiert wurden, werden einem 'Empty State' zugerechnet. Dies ist ebenso, wenn eine Funktion genutzt wird, wenn das Script nicht in irgendeinem State ist, oder wenn derzeitige State keine Funktion implementiert oder übersteuert. Jede in einem State implementierte Funktion muss auch im 'Empty State' (mit identischem Namen, Return-Typen und Parameterliste) implementiert werden und zwar im aktuellen Script oder einem Parent.

Wechseln von States

Um einen State in einem Script zu wechseln, ruft man GotoState auf und übergibt den Namen des States, zu dem man wechseln will, als String. Der State muss in dem aufgerufenen Script nicht existieren. Um in den 'Empty State' zu wechseln, wird ein leerer String übergeben. .

Abfrage des derzeitigen States

Um den derzeitigen State zu erhalten, ruft man GetState auf. Es wird der Name der aktuellen States als String zurück gegeben.

Wie ein State sich auf Funktionen und Events auswirkt

Die zum Laufen ausgewählte Funktion oder das Event wird durch folgenden Algorithmus bestimmt:

  • Überprüft den State des aktuellen Scripts auf die Funktion
  • Überprüft den State des Parent-Scripts auf die Funktion
  • Überprüft den 'Empty State' des aktuellen Scripts auf die Funktion
  • Überprüft den 'Empty State' des Parent-Scripts auf die Funktion

Beispiele

<papyrusscript>

Definiert eine Funktion und einen State mit Übersteuerung
a function and a state with an override

int Function MyFunction()

 Return 1

EndFunction

State MyState

 int Function MyFunction() ; Name, Parameter und Type des Returns müssen der Version 
                           ;im 'Empty State' entsprechen. 
   Return 2
 EndFunction

EndState

Function CallMyFunction()

 int x = MyFunction() ;  Zuweisung von  1, wenn das Script das erste mal läuft ( in keinem State)
 GotoState("MyState")
 x = MyFunction() ; Zuweisung von 2
 GotoState("WrongState")
 x = MyFunction() ; Zuweisung von 1 (Rückfall, weil State in diesem Script nicht existiert,  
                  ; aber in einem Child–Script existieren könnte)

fallback because state doesn't exist in this script, but might in a child)

 GotoState("")
 x = MyFunction() ; Zuweisung von  1 ('Empty State')

EndFunction </tesscript >
<papyrusscript>

Ändern des States im obigen Beispiel in ein Auto-State.

Auto State MyState

 int Function MyFunction() ; Name, Parameter und Type des Returns müssen der Version 
                           , im 'Empty State' entsprechen. 
   Return 2
 EndFunction

EndState

Nun wird x in CallMyFunction() 2, 2, 1, 1 zugewiesen, weil das Script mit MyState beginnt.

</papyrusscript>


Siehe auch