Variablen und Arrays

Variablen speichern Zahlen. Zum Ändern globaler Parameter, wie etwa der Hintergrundfarbe, kennt die Engine vordefinierte Variaben, die durch Funktionen gesetzt werden können. In einem der folgenden Kapitel finden Sie eine Liste dieser vordefinierten Variablen. Zur Definition eigener Variablen und um diese mit einem Initialwert zu versehen, verwenden Sie bitte die folgende Deklaration:

var name;	// uninitialized variable
var name = number; // initialized variable

Diese Deklaration erstellt eine Variable vom Typ var mit dem gegebenen Namen (name). Der Name kann bis zu 30 Zeichen enthalten und muß mit A..Z, a..z oder einem Unterstrich _ beginnen. Wie bei allen anderen Objekten darf auch eine Variable niemals einen bereits anderweitig benutzten Namen wie red, green, blue, x, y, z, pan, tilt, roll etc. haben. Beispiel:

var test; //  declare variable "test"
var enemy = 5; // declare  variable "enemy" and assign the value 5 

 LC  In lite-C können Variablen zudem konstante Ausdrücke und defines zugewiesen werden. Beispiel:

#define SIZE 100
...
var smaller_size = SIZE/2; // assign the value 50 

 !!  Seien Sie vorsichtig beim Zuweisen konstanter Ausdrücke an Variablen. Besteht der konstante Ausdruck lediglich aus ganzen Zahlen (also ohne Dezimalpunkt), wird auch das Ergebnis auf eine ganze Zahl abgerundet. Beispielsweise ist die Konstante (99/2) 49, aber (99.0/2.0) ist 49,5. Ebenso ist die Konstante 1.0/2.0 0.5, aber 1/2 ist 0!

Variablen lassen sich überall im Skript umdefinieren. Es wird nur die neueste Definition verwendet. Beispiel:

var v1 = 7;
... 
var v1 = 13;
erstellt die Variable v1 mit einem Initialwert von13. Allerdings lassen sich Variablen nicht in einen anderen Typ oder eine andere Array-Länge umdefinieren. In lite-C können Engine-Variablen gar nicht neu definiert werden.

In C-Script werden sämtliche nicht initialisierte Variablen automatisch auf 0 initialisiert. Dies geschieht zu Ungunsten der Performance lokaler Variablen.  LC  Daher ist die Autoinitialisierung in Lite-C wählbar und kann mit der PRAGMA_ZERO-Definition angeschaltet werden:

#define PRAGMA_ZERO   // initialize variables

Wird diese Zeile am Anfang des Skriptes eingefügt, werden alle nicht initialisierten globalen und lokalen Variablen automatisch auf Null initialisiert. Funktionsaufrufe sind dann etwas langsamer.

Variablentypen

Computer führen ihre Berechnungen mit begrenzter Genauigkeit durch, daher sind sämtlichen normalen Variablentypen im Bezug auf Genauigkeit und Reichweite Grenzen gesetzt. Das "Arbeitspferd" der Sprache ist die Allzweckvariable var. Sie kann Zahlen, Pointer oder Handles speichern. Zahlen werden im Festpunktformat im Bereich von -999999.999..+999999.999 und mit einer Genauigkeit von 0.001 gespeichert. Anders als Fließkommavariablen, die bei grösseren Zahlen ungenauer sind, behalten var-Variablen ihre Genauigkeit über den gesamten Bereich bei und sind daher für die Koordinaten einer virtuellen Welt wesentlich besser geeignet. Sie werden daher generell für 3D-Koordinaten, Winkel und die meisten anderen numerischen Eigenschaften von Engine-Objekten verwendet. Mit var-Variablen lassen sich auch Zähler und Boolsche Operationen, die mit Fließkommavariablen nicht möglich wären, durchführen.

 !!  Trotzdem haben alle var-Vorteile ihren Preis: gehen Sie aufgrund ihrer Minimal-Schrittbreite von 0.001 beim Berechnen von sehr großen oder sehr kleinen Werten mit var-Variablen mit Vorsicht zu Werke. Eine Multiplikation mit 100 hat beispielsweise eine Ungenauigkeit von 0.001/100 = 0.001%, während eine Division durch 0.01 - mathematisch dasselbe - eine Ungenauigkeit von 0.001/0.01 = 10% erwarten lässt!

 LC  Lite-C unterstützt zusätzlich standard C/C++ ganzzahlige oder Fließkomma-Variablen für Fälle, in denen Sie einen grösseren Bereich mit weniger Genauigkeit oder höhere Genauigkeit mit kleinen Zahlen brauchen:

Typ Grösse Bereich Minimum Genauigkeit*
var 4 bytes -1048577.999 to 1048576.999** 0.001 ~9
long, int 4 bytes -2147483648 to 2147483647 1 ~10
short 2 bytes 0 to 65536 1 ~4
char 1 byte 0 to 256 1 ~2
float 4 bytes -3.4·1038 bis 3.4·1038 1.2·10-38 ~6
double 8 bytes -1.8·10308 bis 1.8·10308 2.2·10-308 ~14

* In Dezimalzahlen.
** In diesem Handbuch oft auch als -999999.999 bis +999999.999 ausgewiesen, was sich leichter merken läßt.

Ganzzhahlige Konstanten im Programm - wie etwa Zeichenkonstanten ('A'), ganzzahlige numerische Konstanten (12345) oder hexadezimale Konstanten (0xabcd) werden als int behandelt. Konstanten, die einen Dezimalpunkt beinhalten (123.456) werden als float behandelt. Wenn Sie also direkt Zahlen ins Skript eingeben, sind diese lediglich von einer Genauigkeit von 6 Dezimalstellen auch dann, wenn sie diese einer double-Variablen zuweisen.

Cast-Operatoren

Normalerweise werden Variablen automatisch in einen anderen Typus konvertiert. Sie können var-Parametern also float- oder int-Variablen zuweisen oder umgekehrt, ohne sich dabei um Typenkonvertierung kümmern zu müssen. Manchmal allerdings, wenn die Konvertierung nicht offensichtlich ist, werden Sie Ausdrücke oder Variablen konvertieren müssen. Wenn Sie beispielsweise eine überladene Funktion, die diverse Variablentypen akzeptiert, aufrufen. In diesem Fall können Sie eine Typenkonvertierung mit einem Cast-Operatoren erzwingen. Ein Cast- (oder Typencast-) Operator ist die der Zielvariablentyp, der in Klammern vor dem zu konvertierenden Ausdruck bzw. der Variablen steht. Beispiel:
float fx = 123.456;
printf("The value of fx is: %.3f",(double)fx); // printf expects the "double" variable type 

Globale, lokale und statische Variablen

Normalerweise werden Variablen ausserhalb von Funktionen definiert. Man nennt sie globale Variablen, sie sind für sämtliche Funktionen zugänglich. Alternativ lassen sich var-Definitionen auch innerhalb von Funktionen plazieren. Dadurch entsteht dann eine lokale Variable. Lokale Variablen sind lediglich innerhalb des Anwendungsbereichs der Funktion gültig - ausserhalb sind sie unbekannt. Existiert eine globale Variable mit demselben Namen wie eine lokale Variable, hat die lokale Variable innerhalb ihrer Funktion Priorität. Beispiel:
function  beep_seven_times()
{
  var i = 0; // define and  initialize a local variable
  while (i  < 7)
  {
    i += 1;
    beep;
    wait(1); //  local variables keep their value during wait()
  }
}                                                                                  

Wenn viele Instanzen (Kopien) derselben Funktion laufen, was bei Entity-Aktionen übllicherweise der Fall ist, benutzt jede Instanz ihren eigenen unabhängigen Satz an lokalen Variablen. Wir empfehlen, lokale Variablen am Anfang der Funktion zu definieren.

 LC  In lite-C kann eine lokale Variable als static (statisch) deklariert werden. Sie wird dann wie eine globale Variable behandelt, auch wenn sie innerhalb einer function deklariert ist, und behält ihren Inhalt auch nach Verlassen der Funktion oder wenn eine andere Instanz der Funktion gestartet wrid. Dies bedeutet, dass sie nur beim ersten Aufruf der Funktion initialisiert wird. Beispiel:

function foo() 
{
  static var initialized = 0;
  if (!initialized) { initialize(); } // initialize only once
  initialized = 1;
  ...
}

 !!  Seien Sie vorsichtig wenn Sie beim Aufrufen anderer Funktionen nicht-statische, lokale Variablen als Argumente übergeben. Lokale Variablen existieren nämlich ausschließlich innerhalb der aufrufenden Funktion. Sobald diese per return oder wait() beendet wird, werden die Argumente ungültig.

In C-Skript verursachen lokale Variablen geringfügige Performance-Einbußen beim Aufruf ihrer Funktion und sie lassen sich nicht für Partikelfunktionen verwenden. Diese Einschränkung gilt nicht für lite-C (In einer Partikelfunktion werden lokale Variablen aber nicht zwischen Frames beibehalten).

Arrays

Wenn Sie mehrere Variablen zu einer Gruppe zusammenfassen, haben Sie einen Array.
var name[n]; // uninitializierter Array
var name[n] = value_1, value_2, ... value_n;  // initialisierter globaler Array in C-Script

Dies erstellt eine Variable, die n Zahlen enthält. Diesen werden in der zweiten Zeile Defaultwerte zugewiesen. Eine solche mehrzahlige Variable nennt man Array. Die Anzahl n ist die sogenannte Länge (length) des Arrays. Beispiel:

var my_array[5] = { 0, 10, 20, 30, 40 }; 

Hiermit wird ein Array von 5 Zahlen, auf die in arithmetischen Ausdrücken durch my_array[0]. my_array[4] zugegriffen werden kann, erstellt. Die Zahl in den [] Klammern - der Index - bestimmt, welcher der 5 Einzelwerte des Array gemeint ist. Beachten Sie, dass es im Beispiel keinen my_array[5] gibt, denn der Index beginnt mit 0. Der Vorteil beim Verwenden eines Arrays im Vergleich zur Definition einzelner Variablen, liegt darin, dass jedweder numerische Ausdruck als Index zugewiesen werden kann. Beispiel:

var i;
for (i=0; i<5; i++) 
{
   my_array[i] = i; // sets the array to 0,1,2,3,... etc.
}

Man muss darauf achten, dass der Index seinen Maximalwert, in diesem Beispiel 4, niemals überschreitet. Ansonsten wird eine Fehlermeldung ausgegeben oder es kann einen Engine-Absturz geben.

In C-Script können lokale Arrays nur die Länge 3 haben. Lokale Arrays und Variablen können nicht als '&' Vektorparameter an andere Funktionen übergeben werden, ausser an Engine-Funktionen. Für lite-C gibt es keine solche Einschränkung.

 !!  Das Initialisieren von Arrays in der Array-Definition unterliegt einigen Einschränkungen: es wird nicht unterstützt für Structs, multidimensionale Arrays, Arrays, die etwas anderes als Zahlen enthalten und für diverse Arrays, die zusammen in einer einzigen logischen Zeile zusammen definiert sind. Das Initialisieren lokaler Arrays macht sie statsich (s. oben) was bedeutet, dass sie beim nächten Aufrufen der Funktion ihre vorherigen Werte behalten.Um sie bei jedem Aufruf der Funktion zu initialisieren, müssen sie explizit auf ihre Anfangswerte gesetzt werden; in etwa so:

function foo()
{
  var my_vector[3];
  my_vector[0] = 10;
  my_vector[1] = 20;
  my_vector[2] = 30;
  ...
  static var my_static[3] = { 1, 2, 3 }; // lite-C: initializing local arrays makes them static 
  ...
} 

Einen Array der Länge 3 nennt man einen Vektor und der wird oft für Positionen, Winkel oder Farben benutzt (s.u.). Arrays können von beliebiger Länge sein, allerdings kann in einer Skript-Datei nur ein Maximum von 500 Initialwerten zugewiesen werden. Falls Sie mehr benötigen, schreiben Sie die Werte in eine separate Textdatei, die sie dann dazu verwenden, den Array per file_... - Anweisung zu füllen. In lite-C gibt es keine Einschränkung der Initialwerte.

 !!  Seien Sie vorsichtig beim Definieren riesiger lokaler Arrays. Sämtliche lokale Variablen werden in einem speziellen Speicherbereich, dem sogenannten Stack gespeichert. Dieser Bereich ist von begrenzter Größe, die davon abhängt wo Ihre Funktion läuft und ob sie von anderen Funktionen aufgerufen wurde. Ein Überschreiten der Stack-Größen bringt jedes Programm zum Absturz. Wenn Sie also aus irgendeinem Grunde riesengroße lokale Arrays aus Zehntausenden von Variablen brauchen oder Sie wollen die Größe der Arrays dynamisch bestimmen, dann verwenden Sie die Methode sys_malloc / sys_free.

Multidimensionale Arrays lassen sich in C-Skript per Multiplikation des Index mit der Array-Breite definieren. Angenommen, Sie brauchen einen zweidimensionalen Array, wie z.B. ein Gitter mit den Höhenwerten 10*20. Dies wird folgendermassen definiert:

var heightmap[200];  // 200 = 10*20 		

Auf den Array-Wert an der Stelle (j,i) kann dann per...

heightmap[j*20 + i] // j = 0..9, i =    0..19

... zugegriffen werden.

 LC  In lite-C lassen sich alternativ (uninitialisiert) multidimensionale Arrays definieren und unter Verwendung mehrerer Indices adressieren.

var heightmap[10][20];
...
heightmap[j][i] = 10; // j = 0..9, i = 0..19

C-Skript unterstützt Arrays sowohl für Variablen als auch für STRING-Pointer innerhalb eines TEXT-Objekts. lite-C unterstützt Arrays für jedweden Variablen- oder Pointertyp.

typedef

 LC  Mit typedef-Statements können Sie in lite-C Ihre eigenen Variablentypen definieren. Beispiel:
typedef long DWORD;
typedef char byte;

...

DWORD dwFlags;
byte mypixel; 

Speichern und Laden von Variablen

Mithilfe spezieller Variablendefinitionen lässt sich das Verhalten der Variablen beim Speichern oder Laden eines Spiels bestimmen:
var_info name; // C-Script: define var_info 
var name_i;    // lite-C: append _i to the variable name

Erzeugt eine Variable oder ein Array, der dann gespeichert wird, wenn SV_INFO für eine game_save-Anweisung gesetzt ist. Info-Variablen eignen sich für User-Einstellungen, wie Lautstärke oder Bildschirmauflösung, die bei Spielstart geladen werden, sich aber beim Laden eines zuvor gespeicherten Spieles nicht verändern sollen.

var_nsave name; // C-Script: define var_nsave 
var name_n;     // lite-C: append _n to the variable name

Diese Variable wird niemals gespeichert. Diesen Variablentypus verwenden Sie z.B. zum Speichern von DLL- und Sound-Handles, die durch eine game_load-Anweisung nicht überschrieben werden dürfen.

Koordinatensystem

Für Koordinaten, Winkel oder Farben werden vordefinierte Vektoren benutzt. In der virtuellen Welt haben wir ein rechtshändiges XYZ-Koordinatensystem bei dem die Z-Achse aufrecht steht. Um etwas auf dem Bildschirm oder in einer Bitmap zu positionieren verwenden wir im Falle von 2-D ein XY-Koordinatensystem in Pixeleinheiten, wobei die Y-Achse nach unten zeigt und der Ursprung in der oberen linken Ecke ist.

Raum- und Zeiteinheiten der virtuellen Welt sind der quant und das tick. Ein Quant ist eine Einheit in WED- und MED-Koordinaten und dabei ist ein Pixel mit 1.0 skaliert.Wie viele Zentimeter einem Quant entsprechen, hängt von der relativen Grösse des Modells ab. Wir empfehlen etwa 2 cm für Spiele auf Grundlage von Personen (Shooters oder Adventures) und ca. 10 cm pro Quant für Spiele, die auf Fortbewegungsgeräten basieren (Kriegsspiele oder Flugsimulatoren). Auf diese Art bekommen sie mit derselben Levelgrösse deutlich grössere Welten. Ein Tick entspricht 1/16 Sekunde - der durchschnittlichen Zeit zwischen zwei Framezyklen auf einem sehr langsamen PC.

Winkel werden in Grad (0 to 360) angegeben und entgegen dem Uhrzeigersinn gezählt. Für Rotationen in drei Dimensionen werden die sogenannte Euler-Winkel benutzt: pan ist der horizontale Winkel (0..360) um die Z-Achse, tilt der vertikale Winkel (-90..+90) um die gedrehte Y-Achse und roll der Winkel (0..360) um die gedrehte und "getiltete" X-Achse. Bei einem pan-Winkel, sind 0 Grad gleichbedeutend mit der positiven Richtung der X-Achsen-Koordinate, die in der Map nach Osten zeigt. 90 Grad sind Norden, 180 Grad Westen und 270 Grad stehen für den Süden.

Farben werden als Blau-, Grün-, Rotkomponentenwerte zwischen 0 und 255 angegeben. Sind alle Komponentenwerte auf 0 gesetzt, ergibt dies Schwarz, sind alle auf 255 gesetzt erhält man Weiss. Der maximale Farbwert von 255 darf nicht überschritten werden. Die Farbreihenfolge bei einem Farbvektor ist blau-grün-rot.

Siehe auch:

Strings, pointers, structs, functions

► Aktuelle Version Online