PageRenderTime 40ms CodeModel.GetById 25ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/docs/sdk/script/Funcs.xml

https://bitbucket.org/randrian/openclonk2
XML | 189 lines | 144 code | 45 blank | 0 comment | 0 complexity | 370cdcc0e8e83f90c3f24cd79eb1fc60 MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
  1<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
  2<!DOCTYPE doc SYSTEM "../../clonk.dtd">
  3<?xml-stylesheet type="text/xsl" href="../../clonk.xsl"?>
  4<doc>
  5<title>Funktionen</title>
  6
  7<h>Funktionen</h>
  8<part>
  9	<text>Eine Skriptfunktion fasst ein bestimmtes St�ck Code zusammen, welches dann von der Engine oder einem anderen Script aufgerufen (also ausgef�hrt) werden kann. Das gesamte Script eines Szenarios oder Objekts ist in solchen Funktionen untergebracht.</text>
 10	
 11	<h>Parameter und R�ckgabewerte</h>
 12	<text>An eine Scriptfunktion k�nnen beim Aufruf bis zu 10 Parameter �bergeben werden. Diese k�nnen dann innerhalb der Funktion ausgewertet und verwendet werden. Beim Beenden kann eine Funktion mit dem Befehl <funclink>return</funclink>() einen einzelnen Wert an den Aufrufer zur�ckgeben.</text>
 13	
 14	<h>Syntax</h>
 15	<text>Eine einfache Funktionsdeklaration k�nnte z.B. folgenderma�en aussehen:</text>
 16	
 17	<code>func MeineFunktion()
 18{
 19  <funclink>Message</funclink>("Meine Funktion wurde aufgerufen!");
 20}</code>	
 21
 22	<text>Das Script der Funktion steht in einem sogenannten Block (der Bereich zwischen '{' und '}' ). Vor diesem Block steht die <strong>Funktionsdeklaration</strong>. Diese beginnt mit "<code>func</code>", gefolgt von dem <strong>Funktionsnamen</strong> (hier: "MeineFunktion"). In der Klammer nach dem Funktionsnamen k�nnen Funktionsparameter definiert werden (s.u.).</text>
 23	<text>Beim Aufruf der Funktion wird die Meldung "Meine Funktion wurde aufgerufen!" ausgegeben.</text>
 24	
 25	<code>func ZeigeZahl(int zahl)
 26{
 27  <funclink>Message</funclink>("ZeigeZahl wurde mit dem Parameter %d aufgerufen!", 0, zahl);
 28}</code>
 29	
 30	<text>Hier wurde ein Parameter mit dem Namen "zahl" vom Typ "int" definiert. Wird beim Aufruf der Funktion ein Parameter angegeben, so erh�lt "zahl" den �bergebenen Wert. Der �bergebene Wert wird in diesem Fall in einer entsprechenden Nachricht ausgegeben.</text>
 31	<text>Ein Aufruf der Funktion "ZeigeZahl" k�nnte z.B. folgenderma�en aussehen:</text>
 32	
 33	<code>ZeigeZahl(42)</code>
 34	
 35	<text>Durch die Ausf�hrung dieses Aufrufes w�rde die Nachricht "ZeigeZahl wurde mit dem Parameter 42 aufgerufen!" erzeugt.</text>
 36	<text>Es ist auch erlaubt, mehrere Parameter zu definieren. Dazu ein Beispiel:</text>
 37	
 38	<code>func ZeigeSumme(zahl1, zahl2, zahl3, zahl4)
 39{
 40  <funclink>Message</funclink>("Die Summe der ersten 4 Parameter ist %d.", 0, zahl1 + zahl2 + zahl3 + zahl4);
 41}</code>
 42	
 43	<text>In diesem Fall wurden vier Parameter benannt. Ihnen wurden die Namen "zahl1" bis "zahl4" zugewiesen (die Parameternamen werden jeweils durch Kommata getrennt).</text>
 44	<text>In der Nachricht wird dann jeweils die Summe der vier �bergebenen Zahlen ausgegeben. Der Funktionsaufruf</text>
 45	
 46	<code>ZeigeSumme(1, 2, 3, 4);</code>
 47	
 48	<text>f�hrt also zu der Nachricht "Die Summe der ersten 4 Parameter ist 10.".</text>
 49	
 50	<h id="parametertypen">Parametertypen</h>
 51	<text>Es ist m�glich, den Typ der �rgebenen Parameter zu erzwingen. Dazu einfach den Namen des entsprechenden Typs (siehe dazu <emlink href="script/Typechecks.html">Typechecks</emlink>) vor den Parameternamen setzen:</text>
 52	
 53	<code>func TypParameterFunktion(object clnk, id def, int anzahl, string msg)
 54{
 55  <emlink href="for.html">for</emlink>(var i = 0; i &lt; anzahl; i++)
 56    <funclink>CreateContents</funclink>(def, clnk);
 57  <funclink>Message</funclink>(msg, clnk);
 58}</code>
 59	
 60	<text>Diese Funktion gibt einem �bergebenen Clonk (<code>clnk</code>) eine Anzahl von Objekten (<code>anzahl</code>) vom angegebenen Typ (<code>def</code>) und gibt die Nachricht <code>msg</code> �ber seinem Kopf aus. Dabei wird bei Funktionsaufruf sichergestellt, dass alle Parameter in den angegebenen Typ konvertiert werden, sofern dies m�glich ist (siehe <emlink href="script/Typechecks.html">Typechecks</emlink>).</text>
 61	<text>Ein Aufruf wie <code>TypParameterFunktion(1, CLNK, "Text", 5)</code> hier w�rde also einen Typfehler ausl�sen.</text>
 62	
 63	<h id="spezial">Vorgabeparameter</h>
 64	<text>Anders als in verschiedenen anderen Programmiersprachen ist es in C4Script immer erlaubt, weniger oder auch mehr Parameter zu �bergeben als in der Funktion definiert (maximal jedoch 10).</text>
 65	<text>Die folgenden Aufrufe der obigen Funktion sind also v�llig legal:</text>
 66	
 67	<code>ZeigeSumme(1, 2);
 68ZeigeSumme(1, 2, 3, 4, 5, 6);</code>
 69	
 70	<text>Beim ersten Aufruf wurden weniger Parameter �bergeben, als in ZeigeSumme deklariert wurden. Die "�bersch�ssigen" Parameter in ZeigeSumme erhalten nun einfach den Wert 0, die Meldung lautet entsprechend "Die Summe der ersten 4 Parameter ist 3." (=1+2+0+0).</text>
 71	<text>Wird ein Parameter nicht �bergeben, so ist das mit der �bergabe von 0 identisch.</text>
 72	<text>Umgekehrt wurden beim zweiten Aufruf <em>mehr</em> Parameter �bergeben als in ZeigeSumme definiert wurden. Der 5. und 6. Parameter werden nun keinem Parameter in ZeigeSumme zugewiesen. Sie k�nnen allerdings noch mittels der Funktion <funclink>Par</funclink>() abgefragt werden [Par(4) und Par(5)]. Da die letzten beiden Parameter von ZeigeSumme also nicht ausgewertet werden k�nnen, wird hier "nur" die Meldung "Die Summe der ersten 4 Parameter ist 10." ausgegeben.</text>
 73	
 74	<h>R�ckgabewerte</h>
 75	<part>
 76		<text>Jede Scriptfunktion gibt einen R�ckgabewert an den Aufrufer (die aufrufende Funktion bzw. die Engine) zur�ck. Dieser Wert wird im Script mittels <funclink>return</funclink>() gesetzt.</text>
 77
 78		<h>Beispiel:</h>
 79		
 80		<code>func Differenz(Zahl1, Zahl2)
 81{
 82  <funclink>return</funclink>(<funclink>Abs</funclink>(Zahl1 - Zahl2));
 83}</code>
 84	
 85		<text>Hier wird die Differenz der ersten beiden Parameter bestimmt und das Ergebnis "zur�ckgegeben". Eine andere Scriptfunktion k�nnte nun diese Funktion benutzen, um die Differenz zweier Zahlen zu berechnen:</text>
 86		
 87		<code>func ZeigeDifferenz(Zahl1, Zahl2)
 88{
 89  <funclink>Message</funclink>("Die Differenz zwischen %d und %d betr�gt %d!", Zahl1, Zahl2, Differenz(Zahl1, Zahl2));
 90}	</code>
 91	
 92		<text>Der Aufruf "ZeigeDifferenz(5, 2)" w�rde also die Meldung "Die Differenz zwischen 5 und 2 betr�gt 3!" erzeugen.</text>
 93	</part>
 94	
 95	<h id="Aufrufb">Aufrufberechtigungen</h>
 96	<part>
 97		<text>F�r jede Funktion kann eine "Aufrufberechtigung" festgelegt werden, die bestimmt, von wo die Funktion aufgerufen werden darf. Hier gibt es drei verschiedene Stufen:</text>	
 98	
 99		<text><table>
100			<row>
101				<col><code>public</code></col>
102				<col>darf von �berall aufgerufen werden, auch aus anderen Scripten (Standard)</col>
103			</row>
104			<row>
105				<col><code>protected</code></col>
106				<col>darf nur aus dem eigenen Script und von der Engine aufgerufen werden</col>
107			</row>
108			<row>
109				<col><code>private</code></col>
110				<col>darf nur aus dem eigenen Script aufgerufen werden</col>
111			</row>
112		</table></text>
113		
114		<text>Die Aufrufberechtigung wird jeweils direkt vor "<code>func</code>" geschrieben:</text>
115		
116<code>private func PrivateFunktion()
117{
118  // Diese Funktion darf nur im selben Script aufgerufen werden!
119}</code>
120	
121		<text>Wird diese Funktion nun von einem externen Script aufgerufen, so gibt die Engine einen Fehler aus.</text>
122		
123		<h>Anmerkung</h> 
124		<text>Da es in manchen F�llen notwendig erscheint, auch eine gesch�tzte Funktion aus einem fremden Script aufzurufen, kann die Aufrufbeschr�nkung mittels <funclink>PrivateCall</funclink> bzw. <funclink>ProtectedCall</funclink> umgangen werden.</text>
125	</part>
126	
127	<h>Globale Funktionen</h>
128	<part>
129		<text>Eine Funktion wird <code>global</code> definiert, indem "<code>global</code>" vor "<code>func</code>" gestellt wird.</text>
130		<text>Eine als <code>global</code> definierte Funktion kann aus jedem Script aufgerufen werden. Ihr G�ltigkeitsbereich stimmt mit denen der Engine-Funktionen �berein. Sie k�nnen damit auch verwendet werden, um Engine-Funktionen zu �berladen und ihre Funktionsweise zu modifizieren.</text>
131		
132		<h>Beispiel:</h>
133
134<code>global func CreateContents(id, pObj, iCnt)
135{
136  var pObj;
137  <emlink href="for.html">for</emlink>(var i = 0; i &lt; iCnt; i++)
138    pObj = <funclink>inherited</funclink>(id, pObj);
139  return(pObj);
140}</code>
141	
142		<text>Definiert die Engine-Funktion <funclink>CreateContents</funclink> neu. Dabei wird sie um einen neuen Parameter iCnt erweitert, der es erlaubt, mehrere Objekte zu erzeugen. Man beachte, dass <funclink>inherited</funclink> innerhalb dieser Funktion der durch sie �berladenen Engine-Funktion <funclink>CreateContents</funclink> entspricht!</text>
143		
144		<h>Achtung!</h>
145		<text>Eine globale Skriptfunktion �bernimmt den Kontext der aufrufenden Funktion. Das bedeutet insbesondere, dass <funclink>this</funclink>() das aufrufende Objekt ist (nat�rlich nur, wenn die Funktion auch aus einem Objekt aufgerufen wurde). Deshalb darf in einer globalen Funktion auch keine objektlokale Variable verwendet werden und auch keine andere lokale Funktion aufgerufen oder lokale Variablen ver�ndert werden! Das folgende Objektscript ist also nicht zul�ssig:</text>
146		
147		<code>local iNummer;
148func ObjektFunktion()
149{
150  <funclink>Log</funclink>("ObjectFunktion: local iNummer hat den Wert %d!", iNummer);
151}
152
153global func GlobaleFunktion()
154{
155  ObjectFunktion(); // Fehler!
156  iNummer++; // Fehler!
157}</code>
158		
159		<text>Beide Versuche, auf objektlokale Elemente zuzugreifen, schlagen fehl. Das ist leicht einsichtig, da GlobalFunktion() ja aus jedem beliebigen Script, also auch aus dem Szenarioscript oder aus dem Script eines anderen Objekts aufgerufen werden kann. Dieses Script besitzt dann h�chstwahrscheinlich auch keine Variable "iNummer" oder Funktion "ObjectFunktion", die benutzt werden k�nnte. Da die Engine dies beim Vararbeiten des Scripts nicht sicherstellen kann, wird ein Fehler ausgel�st.</text>
160		<text>Anmerkung: Soll eine lokale Funktion in einem fremden Kontext aufgerufen werden, so sollte "<code>this()->Funktion(...)</code>" verwendet werden. Dann gibt es nur einen Fehler, wenn die Funktion auch wirklich nicht im Objekt existiert.</text>
161	</part>
162	
163	<h id="referenzen">Referenzen</h>
164	<text>Manchmal ist es n�tig, nicht den Wert einer Variable zu �bergeben, sondern einen "Verweis" auf die Variable selbst.</text>
165	<text>Nehmen wir an, wir wollen eine Funktion schreiben, die die Position des h�chstrangingsten Clonks eines Spielers zur�ckgibt. Dies ist normalerweise ohne Tricks nicht m�glich, da eine Funktion ja nur einen R�ckgabewert hat (die Position hat aber zwei Komponeneten: X und Y).</text>
166	<text>Doch durch Verwendung von Referenz�bergabe als Parameter kann hier die Information trotzdem zur�ckgegeben werden:</text>
167	
168	<code>func GetHiRankPosition(int plr, &amp;x, &amp;y)
169{
170  var oHiRank = <funclink>GetHiRank</funclink>(plr);
171  x = <funclink>GetX</funclink>(oHiRank);
172  y = <funclink>GetY</funclink>(oHiRank);
173}
174
175func Aufruf()
176{
177  var iHiRankX, iHiRankY;
178  GetHiRankPosition(0, iHiRankX, iHiRankY);
179  <funclink>Message</funclink>("Die Position des HiRanks von Spieler 1 ist: %d/%d", 0, iHiRankX, iHiRankY);
180}</code>
181	
182	<text><code>x</code> und <code>y</code> in <code>GetHiRankPosition</code> sind hier <strong>Referenzen</strong>, d.h. wenn man sie setzt, werden die Variablen gesetzt, die man als Parameter angab (in diesem Fall <code>iHiRankX</code> und <code>iHiRankY</code>). Man beachte, dass ein Aufruf wie "<code>GetHiRankPosition(0, iHiRankX + 1, iHiRankY)</code>" zu einem Typfehler f�hrt, da "<code>iHiRankX + 1</code>" keine Variable, sondern eine Zahl ist!</text>
183	<text>Man beachte, dass "<code>&amp;</code>" ein eigenst�ndiger Typ ist, deshalb darf f�r einen Referenzparameter kein weiterer Typ angegeben werden, "<code>int &amp;x</code>" w�re also ung�ltig!</text>
184</part>
185
186<author>PeterW</author><date>Juli 2002</date>
187<author>matthes</author><date>Juni 2004</date>
188
189</doc>