Das erste Spiel
Bevor wir uns direkt an das Programmieren unseres ersten Spieles machen sammeln wir nochmal alles was wir dafür alles an Dateien brauchen.
Zum einen wäre da das Startlevel welches wir mit dem Level Editor als WMB-Datei kompiliert haben, als nächstes brauchen wir noch eini8ge Models welche wir in die WMB-Datei des Levels bereits vorher eingebunden haben und natürlich die Lite-C Datei die wir hinterher in das Level als Main-Skript mit einbinden. Die Lite-C Datei muüssen wir allerdings erstmal schreiben um diese einbinden zu können.
Nun schauen wir in den SED und da Informatiker natürlich faul sind und sich Tipparbeit sparen wollen gibt es auch hier Hilfen. Wir nehmen fertige Code-Templates für die Main-Funktion und die Header. Danach sollte folgendes im Skript stehen:
1 ///////////////////////////////
2 #include <acknex.h>
3 #include <default.c>
4
5 ///////////////////////////////
6
7 function main()
8 {
9 vec_set(screen_size,vector(800,400,0));
10 vec_set(screen_color,vector(50,1,1)); // dark blue
11 vec_set(sky_color,vector(50,1,1)); // dark blue
12 video_window(NULL,NULL,0,"My New Game");
13 d3d_antialias = 1;
14 shadow_stencil = 3;
15
16 level_load("my_level.wmb");
17 vec_set(camera.x,vector(-250,0,50));
18 vec_set(camera.pan,vector(0,-15,0));
19
20 }
Die einzelnen Zeilen habe ich bereits im Grundlagen Teil des Workshop's erklärt und deshalb werde ich hier gleich zur Sachen kommen und diese Zeilen verändern bzw. anpassen.
Die Zeile 9 des Skripts ist ja zur bestimmunbg der Fenstergröße und dies können wir entweder erstmal so lassen oder wir verändern die Werte passend.
Momentan steht da eine definition für ein Fenster von 800x600 da wir aber auch was auf dem Bildschirm sehen wollen würde ich das auf mindestens 1280x720 nehmen.
Darunter die beiden Zeilen für die Hintergrund und Himmelfarbe lassen wir erstmals ausser acht und gehen gleich zu Zeile 12 in die Fensterdefinierung. Da ändere ich immer nur den hinteren Teil wo die Textzeile definiert wird, indem ich meistens den Namen des Spiel eintrage.
Wieder die beiden Zeilen darunter brauchen wir auch erst später genau wie die letzten beiden Zeilen und deshalb gehe ich mal in Zeile 16 und geben das zu ladene Level ein. In unserem Fall wäre das das Level „Tutorial.WMB“
Zum Schluss des ersten Schrittes geben wir oben im Header-Teil des Skriptes ein neues Include ein. Damit wir auch die Kamera im Level bewegen können müssen wir noch die Grundlegenden Kamera Steuerungsfunktionen einbinden indem wir einfach oben „#include <camera.c>“ eingeben.
Damit wir die Kamera im Spiel auch wirklich bewegen können muss noch unten in der Main-Funktion ein vordefinierter Befehl hinzugefügt werden "def_move();". Dieser steht in der Datei "camera.c" die wir zuvor im Header hinzugefügt haben.
Bisher hat sich bei dem Skript nicht viel getan und sollte aber trotzdem bis hierher etwa so aussehen:
1 ///////////////////////////////
2 #include <acknex.h>
3 #include <default.c>
4 #include <camera.c>
5
6 ///////////////////////////////
7
8 function main()
9 {
10 vec_set(screen_size,vector(1280,720,0));
11 vec_set(screen_color,vector(50,1,1));
12 vec_set(sky_color,vector(50,1,1));
13 video_window(NULL,NULL,0,"Tutorial Spiel");
14 d3d_antialias = 1;
15 shadow_stencil = 3;
16
17 level_load("Tutorial.wmb");
18 vec_set(camera.x,vector(-250,0,50));
19 vec_set(camera.pan,vector(0,-15,0));
20 def_move();
21 }
Dieses Skript speichern wir jetzt unter einem beliebigen Namen im Verzeichniss des Spieles.
Als nächstes müssen wir das Skript dem Hauptlevel zuweisen. Dies muss man machen da man im späteren Entwicklungsverlauf den einzelnen eingebundenen Entitys Actionen zuweisen muss und ohne zugewiesenens Skirpt weiß der Level Editor nicht woher er die Actionen nehmen soll.
Dies machen wir im Level Editor indem wir auf „Files / Map Properties“ klickt und dann in dem kleinen geöffneten Fenster neben der Skriptzeile auf das Ordnersymbol klickt und das zuzuweisende Skript auswählt und bestätigt. Der Name des Skriptes müsste dann in der Skriptzeile stehen. Das kleine Fenster kann jetzt geschlossen werden und nun muss das Level nur nochmals neu kompiliert werden um das zugewiesenen Skript noch fest in die kompilierte Level-Datei WMB einzubinden.
Nun ist das Skript vollkommen zugeteilt und wir können das Spiel über die Run Funktion des SED's starten. Dabei gibts es die möglichkeit alles zu kompilieren und anzuzeigen über F5 und nur das Gegenwertig geöffnete Skript zu kompilieren mit F6. Wir wollen aber alles kompilieren und drücken somit die Taste F5.
Nun müsste sich nach dem kleinen Compiler-Fenster das eigentliche Spielfenster öffnen.
Wenn kein Fehler beim Kompilieren aufgetreten ist müsste das Fenster jetzt genau die Größe haben die wir Oben angegeben haben 1280x720 in 16:9 und wir müssten einen Blick von weiter oben im Raum mit einer leichten Neigung nach unten haben. Diese Kamerapositionen wurde im Skirpt in den Vorletzten Zeilen mit dem Vector-Setzungs-Befehlen "vec_set(...)" definiert. Bei "vec_set(camera.x,vector(-250,0,50);" wurde die Kameraposition definiert an Position -250, 0, 50 im Level gesetzt und in der Zeile darunter wurde mit dem Befhel "vec_set(camera.pan,vector(0,-15,0);" Eine Rotation der Kamera um 15° negativ an der X-Achse definiert. Wem diese Einstellung nicht gefällt kann das Spiel schliessen und die Parameter in den Beiden Zeilen entweder ändern oder die beiden Zeilen direkt löschen. Beim löschen muss dann nur im Level eine sogenannte Position setzen. Diese ist im Level Editor und Object -> Add Position zu finden. Da in unserem Level jedoch eine Position bereits vorhanden ist brauchen wir das jedoch nicht. Nun können wir entscheiden, wollen wir die Kameraposition und deren Neigung im Skript definieren oder über die Position im Level. Für Anfänger würde ich das Zweite empfehlen, da dieses einfacher ist. Wer sich nicht entscheiden kann kann die beiden Befhelen erstmal "auskommentieren" mit "//" Vor dem jeweiligem Befehl.
Dies jetzt zur Kameraposition. Da wir zwar im Level einen Charakter haben, jedoch keine zugewiesene Action in der die Kameraführung in Ego- oder Third-Person ist, bewegen wir die Kamera über dem "def_move();" Befhel mit den "Pfeiltasten" zum bewegen und rotieren, den "Bild auf" und "Bild ab" Tasten zum rauf und runter schwenken und die "Pos1" und "Ende" Taste zum Heben und Senken der Kamera. Damit können wir uns solange durch das Level bewegen.
Jetzt können wir entscheiden was wir als nächstes machen wollen. Ich würde mich jetzt entweder an das Optische, sprich GUI usw. machen oder weiter an die Spielmechanik wie z.B. das das wir nun unserem Charakter leben einhauchen.
Jetzt können wir entscheiden was wir als nächstes machen wollen. Ich würde mich jetzt entweder an das Optische, sprich GUI usw. machen oder weiter an die Spielmechanik wie z.B. das das wir nun unserem Charakter leben einhauchen.
Ich schätze aber mal das ihr euch alle eher für das zweite, sprich die Spielmechanik interessiert, da ich ja so oft zu dem Skripten und dem SED genötigt wurde.
Fangen wir also mal damit an unserem Charakter leben einzuhauchen.
Als erstes müssen wir eine Action schreiben die wir unserem Charakter hinterher zuweisen müssen und in diese Action schreiben wir die Grundlegenden Zeilen damit wir den Charakter bewegen können. Da diese Zeilen auf einander aufbauen und zusammenhängen schreibe ich sie jetzt mal in einem Rutsch auf:
1 action chara()
2 {
3 my.pan += (key_a-key_d)*5*time_step;
4 var distance = (key_w-key_s)*5*time_step;
5 c_move(me, vector(distance, 0, 0), NULL, GLIDE);
6 my.ANIMATION += 2*distance;
7 ent_animate(me,"walk",my.ANIMATION,ANM_CYCLE);
8 c_trace(my.x,vector(my.x, my.y ,my.z-1000),IGNORE_ME |
9 IGNORE_PASSABLE);
10 }
Das mag zwar für den Anfänger jetzt etwas überfordernd sein aber ich werde nun diese Zeilen stück für Stück erleutern und deren Bedeutung erklären.
Die ersten Beiden Zeilen in der geschweiften Klammer (Zeile 3+4 im Beispiel) definieren mit welchen Tasten sich der Charakter bewegen lassen soll. Diese wären die vordefinierten Strings "key_a" für die Tatse A, "key_d" für die Taste D usw. In der ersten Zeile steh davor noch ein "my.pan" Diesi ist ein Pointer (my.) welcher sich auf die Entity bezieht der wir diese Action später zuweisen und "pan" einer Vordefinition für Rotationen von Objekten an der Y-Achse.
In der zweiten Zeile wird vor der Definition der Tasten eine Variable deklariert. Die Variable "distance". Diese definierte Variable wird später benötigt um die Laufanimation und die Bewegungsgeschwindigkeit berechnen zu können. Hinter beiden Zeilen steht noch ein "*5*time_step;" und die Tastendefinition ist in Klammern, warum? Ganz einfach das die Tasten in Klammer stehen soll heißen das er diese beiden Tasten in Relation zu einander sehen soll, das heißt bei der einen Taste soll er eine positive Rotation an der Achse machen und bei der anderen eine entgegengesetzte, also ein negative Rotation. Jetzt als Beispiel für die erste Zeile. Das "*5" steht für den Geschwindigkeitsfaktor wie die gedruckte Taste pro Tick (*time_step;) berechnet werden soll. Deiser Wert kann variieren, sollte jedoch in beiden Zeilen identisch sein um Gleichmassige Bewegungen zu garantieren.
Nun zur nächsten Zeile, c_move. Diese Zeile bzw. Dieser vordefinierte Befehl wird benötigt damit sich unser Charakter bewegt. C_Move steht als Abkürzung für Charakter Move z.dt. Charakter Bewegung. Diese Funktion benötigt einige angegeben Parameter um zu funktionieren. Darunter die Entitiy die sich bewegen soll hier einfach mit "me" gefüllt, da wir diese Action der Entity später im Level Editor hinzufügen. Danach der Vector für die Bewegungsstrecke in Entity-Koordination, dem sogenannten relativen Bewegungsvektor. Hierfür benötigen wir unsere zuvor berechnete Variable "distance", welche wir als Vektor an erster Stelle definieren, der Rest ist 0. Danach die Bewegungsstrecke in Welt-Koordination, dem sogenannten absoluten Bewegungsvektor. Den benötigen wir nicht da wir ein Spiel da wir den Charakter nicht nach festen Weltkoordination sondern Frei bewegen wollen, also setzte wir da einfach "NULL". Zum Schluss noch der Kollisionsparamter. Dieser gibt an an was unser Charakter abprallen, durchgehen und entlangrutschen soll. Wir wollen das er über den Beoden und anderen Objekten entlanggleitet also setzte wir "GLIDE". Wenn der Charakter auf dem Boden bleiben soll muss GLIDE gesetzt sein, weil sonst wenn wir ihn nachher auf den Boden setzten würde er durch das Level in Nichts stürzen!
Die nächsten zwei Zeilen beschäftigen sich mit der Animation des Charakters. In der ersten (Zeile 6 im Beispiel) wird die Animationsgeschwindigkeit anhand der Definition "ANIMATION" mit einer simplen multiplikationen des zuvor berechneten Variable "distance" berechnet.
Allerdings haben wir diese Definition jetzt hier stehen, müssen sie aber noch im Skript definieren.
Hierfür gehen wir wieder in den Header bereich unseres Skripts und schreibe dort folgende Zeile:
1 #define ANIMATION skill1
Für Definition und Includes sind keine Semicolons " ; " notwendig!
Nun gehen wir wieder zu unserer Action und sehen uns die vorletzte Zeile an.
Der vordefinierte Befehl "c_trace" sendet einen nicht sichtbaren Strahl, ähnlich wie ein Laserpointer, vom Vektor "from" zum Vektor "to" und prüft ob sich dort Hindernisse befinden.
Der Vektor "from" ist hier mit "my.x" angeben damit ist die X-Achse unseres Charakters gemeint. Gesendet soll dieser an den Vektor "to". Dieser ist über einen Vektor definiert mit my.x, my.y und my.z-1000. In dieser Kombination mit dem Vektor "from" heißt das der Strahl geht nach unten und setzt de nCharakter auf den ersten "soliden" Untergrund den er ausmacht. Zuletzt stehen da noch Kollisionsparamter die dieser Strahl ignorieren soll. Dieser wäre IGNORE_ME, das heißt der Strahl soll die Entitiy selbst ignorieren und IGNORE_PASSABLE, alle Passablen Objekte ignorieren.
Dies wäre jetzt die, FAST, gesammte Action die benötigt wird um den Charakter dem wir diese Action zuweisen zu steuern.
Es fehlt nurnoch eine einzige Sache damit diese Action auch funktioniert. Der gesammte Code in den geschweiften Klammern muss noch in eine Endlossschleife gepackt werden.
Dies sieht dann wie folgt aus:
1 action chara()
2 {
3 while(1)
4 {
5 my.pan += (key_a-key_d)*5*time_step;
6 var distance = (key_w-key_s)*5*time_step;
7 c_move(me, vector(distance, 0, 0), NULL, GLIDE);
8 my.ANIMATION += 2*distance;
9 ent_animate(me,"walk",my.ANIMATION,ANM_CYCLE);
10 c_trace(my.x,vector(my.x, my.y ,my.z-1000),IGNORE_ME |
11 IGNORE_PASSABLE);
12 wait(1);
13 }
14 }
Soweit so gut. Es fehlt nurnoch eine Zusatzfunktion in der wir die Kamera auf den Charakter fixieren. Diese Funktion ist jedoch ganz einfach und ist schnell geschrieben. Dafür gehen wir nun entweder über oder unter die Action und schreiben dort die Funktion der Kamerafixierung.
Hierbei könnt ihr jetzt auswählen ob ihr eine Ego oder eine Third-Person Perspektive haben wollt.
Der vollständiogkeit halber schreibe ich jetzt mal für beide Perspektiven die Funktion hin. Sehr unterscheiden werden sie sich jedoch nicht, quasi nur an einer einzigen Stelle.
Third-Person Perspektive
1 function camera_follow(Entity*ent)
2 {
3 while(1)
4 {
5 vec_set(camera.x, vector(-150,10,50));
6 vec_rotate(camera.x, ent.pan);
7 vec_add(camera.x, ent.x);
8 vec_set(camera.pan, vector(ent.pan, -10,0));
9 wait(1);
10 }
Ego Perspektive
1 function camera_ego(Entity*ent)
2 {
3 while(1)
4 {
5 vec_set(camera.x, vector(0,0,0));
6 vec_rotate(camera.x, ent.pan);
7 vec_add(camera.x, ent.x);
8 //vec_set(camera.pan, vector(ent.pan, 0,0));
9 wait(1);
10 }
In der ersten Zeile wo die Funktion definiert wird sehen wir eine Definition für einen Übergebenen ENTITY Parameter namens "ent". Dieser wird benötigt um die Funktion mit dem Actions internen Variablen und Definition kommunizieren zu lassen.
In der 5. Zeile sehen wir eine Vektor-Set Definition in der der Vektor in relation zum Charakter posiotioniert wird über die X-,Y-,Z-Koordinaten.
In den beiden Zeilen darunter wird die Rotation und die Fixierung der Kamera definiert. Mit "vec_rotate" wird die Rotation der Kamera passend zur Charakterrotation definiert und darunter die Fixierung, das die Kamera sich passend Dreht aber auf den Charakter fixiert bleibt und mitschwenkt. Darunter wird nurnoch eine leichte Neigung der Kamera um 10° nach Unten in Sichtrichung definiert. Diese macht jecoch nur in der Third-Person Perspektive etwas eindruck und ist auch nur Schönheitssache. Im Code für die Ego Perspektive habe ich diesen deshalb auskommentiet, da man diese Zeile dort eigentlich nicht braucht.
Nun müssen wir nurnoch die Funktion mit der Action verknüpfen. Dafür setzten wir die Funktion nurnoch in unsere Action noch über die Schleife und schreiben noch in die Klammer hinter der Funktion den Parameter "me". Damit wird dieser dann auch an die Funktion übergeben.
Jenachdem ob die Funktionb jetzt über oder unter der Action steht muss ggf. Noch ein Prototyp an Anfang des Skriptes gesetzt werden, dies ist jedoch nur nötig wenn die Funktion utner der Action steht.
Das komplette Beispiel für die hinzugefügten Skriptzeilen:
1 #define ANIMATION skill1
2
3 function camera_follow(ENTITY* ent);
4
5 action chara()
6 {
7 camera_follow(me);
8 while(1)
9 {
10 my.pan += (key_a-key_d)*5*time_step;
11 var distance = (key_w-key_s)*5*time_step;
12 c_move(me, vector(distance, 0, 0), NULL, GLIDE);
13 my.ANIMATION += 2*distance;
14 ent_animate(me,"walk",my.ANIMATION,ANM_CYCLE);
15 c_trace(my.x,vector(my.x, my.y ,my.z-1000),IGNORE_ME |
16 IGNORE_PASSABLE);
17 wait(1);
18 }
19 }
20
21 function camera_follow(Entity*ent)
22 {
23 while(1)
24 {
25 vec_set(camera.x, vector(-150,10,150));
26 vec_rotate(camera.x, ent.pan);
27 vec_add(camera.x, ent.x);
28 vec_set(camera.pan, vector(ent.pan, -10,0));
29 wait(1);
30 }
31 }
Nun müssen wir unserem Charakter im Level noch die Action "chara" zuweisen.
Dafür gehen wir im Level Editor in unserem Tutorial Level auf den Charakter. Nun erscheint unten Links ein neues Register. Dort wählen wir die Kategorie "Behaviour" aus.
Direkt in der zweiten Zeile der neue Registerkarte sehen wir die Zeile "Action". Darunter eine Zeile in der "ndef" steht, das bedeutet Nicht Definiert und ein kleines Ordner Symbol und ein Kreuz.
Nun klicken wir auf das kleine Ordner-Symbol. Es müsste sich ein Fenster öffnen mit dem Titel Choise Action oder Acion wählen, je nach Spracheinstellung. Dort müsste unsere gerade geschriebene Action "chara" drinstehen. Wir wählen diese aus und bestädigen unsere Auswahl.
Nun müsste unter der Zeile Action, in der Registerkarte, unsere Action "chara" stehen statt wie zuvor "ndef". Nun müssen wir das Level noch einmal Kompillieren.
Wenn das Level neu Kompilliert wurde gehen wir wieder auf das Skript im SED und starte es mit einer der Taste F5.
Unser Level müsste ohne eine Fehlermeldung von sich zu geben, wenn alles Richtig ist, starten und die Kamera müsste nun nicht mehr wie zuvor vor unserem Charakter auftauchen sondern hinter ihm und wenn wir jetzt die Taste "W" drücken müsste er nach Vorne laufen.
Wenn er beim Druck der anderen Taste auch das macht was er soll war alles Richtig und nun können wir snstatt mit der Kamera mit unserem Charakter das Level erkunden.
Die gerade erleuterte Funktion ist noch nicht perfekt aber beschreibt wie so eine Charaktersteuerung Grundlegend auszubauen ist. Ein Beispiel das auch die Kollisionserkennung mit dem setzten des Charakters auf den Boden auch noch nicht ganz funktioniert seht ihr wenn wir in unserem Tutorial Level die Schräge hochgehen zur oberen Ebene und dann einfach über den Rand der Plattform laufen.
Wenn du die Aktivitäten von mir unterstützen willst spende von mir aus mit einem klick über PayPal
©2011-2021 LordDevil aka. Dennis-R. Guthe