workshop13

Top  Zurück  Weiter

Workshop 13: Das Verwenden der Tastatur

Wenn Sie ein Spiel nicht steuern können, können Sie ebensogut einen Film anschauen. Lite-C ermöglicht es aber mittels Tastatur, Maus, Joystick und simpler Lite-C -Anweisungen, das Geschehen im Level zu kontrollieren. Wollen Sie andere Hardware-Elemente (z. B. eine Leuchtpistole) mit der Engine zusammen verwenden, können Sie mithilfe des Source Developer Kids (SDK) ein Interface in C++ oder Delphi entwickeln.

Wenn Sie eine Taste Ihrer Tastatur drücken, kann lite-C verschiedene Dinge machen:

1) Lite-C setzt eine vordefinierte Variable auf 1. Das Schöne daran ist, dass diese vordefinierte Variablen (zumindest im Englischen) bedeutungsvolle Namen haben wie:

key_a, key_b, key_shift, key_space, key_pause, key_f1, etc.

Sie können prüfen, ob (key_a == 1), und wenn diese Aussage wahr ist, wissen Sie mit absoluter Sicherheit, dass jemand auf die "A"-Taste gedrückt hat.

2) Lite-C kann einen Scan-Code generieren. Das ist eine einfache Zahl, ihr Wert hängt allerdings davon ab, welche Taste gedrückt wurde. Sie können mit Hilfe von key_lastpressed den Wert des Scan-Codes überprüfen und dadurch feststellen, welche Taste gedrückt wurde. Weitere Informationen zu diesen Schlüsselworten, sowie eine Tabelle aller Scan-Codes finden Sie im Lite-C -Handbuch.

Diese Methode wird nur in einigen wenigen Fällen, wie der Neudefinition der Tasten benutzt. Im Acknex User Magazine (AUM) finden Sie ein paar Beispiele bei denen Scan-Codes verwendet wurde.

3) Lite-C kann auf Tastendruck eine bestimmte Funktion ausführen, wenn wir diese denn einer bestimmten Taste zugewiesen haben. In einem vorangegangenen Workshop, dem über Pointer, habe ich ein Beispiel dazu verwendet:

function move_up()
{
  wizard.z += 5;
}
...
on_u = move_up;
...

Dieses Beispiel startet eine vorher definierte Funktion namens "move_up" sobald wir auf die "U"-Taste drücken (Ob "U" oder "u" ist dabei egal). Beachten Sie bitte, dass der Funktions-Name ohne Klammern angegeben werden muss.

Wichtiger Hinweis
Wenn Sie noch einiges mehr über Lite-C lernen möchten, empfehle ich Ihnen, mein AUM zu lesen. Der Code in den Artikeln ist Schritt für Schritt erläutert. Oh, aber kopieren Sie keinen Code aus dem Magazin in Ihre Skripte, denn er ist ein wenig vereinfacht. - Auf der ersten Seite einer jeden Ausgabe finden Sie einen Link zu voll funktionsfähigen, herunterladbaren Lite-C -Dateien.

Machen wir uns an die Arbeit! Starten Sie Lite-C, starten Sie script13 und Sie sehen die drei oben aufgelisteten Tastatur-Methoden in Aktion (Die hübsche Sky-Textur wurde von Mighty Pete erstellt). Drücken Sie [W] oder [S], um die Kamera nach oben und unten zu neigen.[A] und [D] ändern den Pan-Winkel der Kamera und [1] erhellt den Sky, während [2] das Licht wieder dimmt. Um die Kamerawinkel in die ursprüngliche Position zurück zu versetzen, drücken Sie die [R]-Taste. Und zwischen Fenster- und Vollbildmodus läßt sich per Tastenkombination [Alt] + [Eingabe] hin- und herschalten.

bloodshot

Ich bin sicher, es wird Sie nicht allzusehr überraschen, zu hören, dass all diese Dinge mit einer kleinen Skript-Datei geschaffen wurden:

////////////////////////////////////////////////////////////////////
#include 
#include 

////////////////////////////////////////////////////////////////////

ENTITY* my_sky;

function bright_lights()
{
	vec_add(my_sky.blue,vector(10, 10, 10));
}

function dim_lights()
{
	vec_add(my_sky.blue,vector(-10, -10, -10));
}

function main()
{
   on_1 = bright_lights;
   on_2 = dim_lights;
   
	level_load ("");
	my_sky = ent_createlayer("blood_gorge+6.tga", SKY | CUBE | SHOW, 0);
	
	while (1)
	{
		if (key_w) camera.tilt += 2 * time_step; 
		if (key_s) camera.tilt -= 2 * time_step; 
		if (key_a) camera.pan += 2 * time_step;
		if (key_d) camera.pan -= 2 * time_step;
		if (19 == key_lastpressed) // wurde die [R]-Taste gedrückt
		{
			camera.pan = 0; // stelle den ursprünglichen pan wieder her
			camera.tilt = 0; // und die tilt-Winkel
			vec_set(my_sky.blue,vector(128,128,128));	// setze eine mittlere Sky-Helligkeit 
		}
		wait (1);
	}
}

Zuallererst besprechen wir die Methode, die zum Erstellen des hübschen Himmels verwendet wurde:

level_load (" ");
my_sky = ent_createlayer("blood_gorge+6.tga",SKY | CUBE | SHOW, 0);

Wir laden, genauso wie wir's im 10 Workshop gemacht haben, ein Level. Diesmal ist es aber, wie sich an dem leeren Namensstring, der von unserer level_load-Funktion benutzt wird, erkennen läßt, ein absolut leeres Level. Die folgende Codezeile erstellt einen Himmel; die Anweisung ent_createlayer erstellt eine (2D) "gelayerte" Entity, was bedeutet, dass wir diverse Entities übereinander auf verschiedene Layer aufbringen können. Unser Beispiel plaziert den Sky auf den ersten Layer (layer = 0). Sky-Entities sind gelayerte Entities und weil eine gelayerte Entity ebenso in einer 2D-Welt leben kann, läßt sie sich auch ohne "echtes" 3D-Level erstellen.

Wie sich vermutlich gedacht haben, ist "blood_gorge+6.tga" der Name der sechsseitigen Sky-Bitmap, die sich im Ordner workshop13 befindet. SKY, CUBE und SHOW sind Flags, die angeben, dass die Entity ein sichtbarer Sky-Würfel ist. Im Handbuch zu Lite-C finden Sie die komplette Liste der Sky-Flags.

Der fortgeschrittene Programmierer würde sagen, daß ent_createlayer einen Pointer auf die erstellte Entity zurückliefert. Am Anfang des Skripts haben wir den ENTITY* -Pointer namens "sky" definiert, ent_createlayer erstellt die Sky-Entity und unsere Codezeile "my_sky = ent_createlayer("blood_gorge+6.tga",SKY | CUBE | SHOW,0);" sagt der Engine, daß unsere neu erstellter Sky my_sky heißen wird. Alles klar?

Zeit, den Inhalt unseres while-Loops zu besprechen:

while (1)
{
   if (key_w) camera.tilt += 2 * time_step;
   if (key_s) camera.tilt -= 2 * time_step;
   if (key_a) camera.pan += 2 * time_step;
   if (key_d) camera.pan -= 2 * time_step;
   if (19 == key_lastpressed) // wenn die [R]-Taste gedrückt ist
  {
    camera.pan = 0; // stelle den ursprünglichen-Pan wieder her
   
camera.tilt = 0; // und tilt-Winkel
   
vec_set (my_sky.blue, vector(128,128,128)); // setze eine mittlere Sky-Helligkeit
  }
 wait (1);
}

Drücken wir die Taste [W], erhöht der Code den tilt-Winkel der Kamera indem er 2 * time_step drauf addiert (Sie erinnern sich doch noch an time_step aus dem 10. Workshop?). Drücken wir [S], verkleinert der Code den tilt-Winkel. Durch Drücken von [A] wird camera.pan erhöht und per [D] verringert.

Erst kürzlich haben wir die Punkt-Methode benutzt und so erinnern Sie sich bestimmt noch an deren generelle Form: object.property. Die Kamera (unsere Sicht innerhalb der 3D-Welt) ist ebenfalls ein Objekt und so können wir auch ihre Eigenschaften wie Winkel, Position, Ambient etc. per Punkt-Methode verändern. Hier verwenden wir ein paar von den Kürzeln fortgeschrittener Programmierer. Wenn wir zwei Ausdrücke miteinander vergleichen, wird eine Variable, die ungleich Null ist, immer als wahr angesehen. Dies bedeutet, dass, wann immer wir die [W]-Taste drücken, (key_w) wahr wird (es wird auf 1 gesetzt). Daher können wir so etwas wie "if (key_w)" benutzen - es funktioniert genauso gut wie "if (key_w == 1)". Noch etwas: wir haben, damit der Code kürzer wird, die Kamera-Anweisungen direkt zu den if-Vergleichen geschrieben. Sie sollten immer an diese vereinfachten Anweisungen denken:

camera.tilt += 2 * time_step;

... die exakt denselben Job machen wie ihre großen Brüder:

camera.tilt = camera.tilt + 2 * time_step;

  ... usw. Dieselben Kürzel lassen sich für jedweden anderen, von der Engine benutzten mathematischen Operatoren verwenden. Werfen wir einen Blick auf den letzten Teil der Schleife, der den Scan-Code (die zweite Tastatur-Methode) verwendet:

if (19 == key_lastpressed) // Ist "R" gedrückt
 
camera.pan = 0;
  
camera.tilt = 0;
  
vec_set (my_sky.blue, vector(128,128,128)); // mittlere Helligkeit

}

Die vordefinierte Variable key_laspressed speichert den Scan-Code für die zuletzt gedrückte Tastatur-Taste. Und immer wenn Sie [R] drücken, wird key_lastpressed auf 19 (den Scan-Code, der der "R"-Taste entspricht) gesetzt. Die "if"-Anweisung prüft, ob [R] gedrückt wurde (mit dem konstanten Wert auf der linken Seite, so, wie wir es im letzten Workshop gelernt haben) und wenn dem so ist, werden die Kamerawerte zurückgesetzt (die Initialwerte der Winkel sind pan = 0 und tilt = 0).

Obwohl sie sich dorthin konvertieren lassen, haben die von der Engine generierten Scan-Codes nichts mit den ASCI- oder ANSI-Codes zu tun (wenn Sie von ASCI- und ANSI-Codes keine Ahnung haben, machen Sie sich nicht die Mühe, den letzten Satz verstehen zu wollen). Hinweis: im Referenzhandbuch finden Sie eine Tabelle sämtlicher Scan-Codes für jede Taste auf der Tastatur.

Die letzte Zeile innerhalb der if-Verzweigung setzt die Helligkeit des Sky auf einen mittleren Wert. Wieder verwenden wir die Punkt-Methode, nur, dass unser Objekt diesmal die Sky-Entity ist. Über ihre Blau-, Grün, und Rotwerte hat jede Entity eine definierbare Farbe. Diese Werte reichen von 0 bis 255. Indem wir sie also auf 128 setzen, bekommen wir eine mittlere Farbe und Helligkeit. Um alle drei Werte in einer einzigen Codezeile setzen zu können, verwenden wir hier, genau wie im 10. Workshop, die vec_set-Anweisung. Der Blau-Wert dient auch als Farbvektor blau-grün-rot. Es ist dasselbe wie der x-Wert, der in Workshop10 als Positionsvektor x-y-z- diente.

Werfen wir zum Schluß noch einen Blick auf die beiden Funktionen, die starten, sobald wir auf die Tasten 1 oder 2 drücken:

function bright_lights()
{
  vec_add (my_sky.blue, vector(10,10,10));
}

function dim_lights()
{
  vec_add (my_sky.blue, vector(-10,-10,-10));
}

...

on_1 = bright_lights;
on_2 = dim_lights;

...

Die erste Funktion (bright_lights) erhöht die Helligkeit des Skys indem sie einen Wert auf seine Farben aufaddiert. vec_add funktioniert ähnlich wie vec_set, anstatt die Werte wie vec_set zu setzen, addiert es aber lediglich drei Werte. Unsere Codezeile vec_add:

vec_add (my_sky.blue, vector(10,10,10));

... läßt sich durch:

my_sky.blue += 10;
my_sky.green += 10;
my_sky.red += 10;

... ersetzen.

Dieses Stück Code hat denselben Effekt, ist aber länger und etwas langsamer. Die zweite Funktion, die auf ähnliche Weise läuft, reduziert die Helligkeit des Sky indem sie jede Farbkomponente (blau, grün, rot) desselben um 10 verringert. Beachten Sie wieder einmal die fehlenden Klammern bei den beinen Funktion in den Zeilen "on_1 = ..." und "on_2 = ..." der Main-Funktion. Hätten wir Klammern hinter die Funktionsnamen gesetzt, würden die Funktionen bright_light und dim_light ausgeführt und nicht den Tasten zugewiesen werden!

Die Scan-Code-Tastaturmethode wird nicht sehr häufig angewendet. Wenn Sie eine bestimmte Aktion oder Funktion, die etwas ausführt und dann zu laufen aufhört (das Öffnen einer Tür, Licht anschalten, zwei Zahlen addieren etc.) starten wollen, sollten Sie die "on_x = tu_irgendwas;"-Methode (ersetzen Sie "x" durch irgendeine andere Taste) nehmen. Die "if (key_x)"-Methode und einen while-Loop verwenden Sie zum Kontrollieren einer Aktion oder Funktion, die dazu gedacht ist ständig zu laufen (Spielerbewegung, die Kamera, ein Fahrzeug, ein Schläger etc.).

Weiter: Die Maus