11.12.2012 Aufrufe

3D GAMESTUDIO-Magazin Ausgabe 01 | Oktober 20051

3D GAMESTUDIO-Magazin Ausgabe 01 | Oktober 20051

3D GAMESTUDIO-Magazin Ausgabe 01 | Oktober 20051

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │1


Vorwort<br />

Inhalt<br />

Liebe Leserin, lieber Leser,<br />

mit dieser <strong>Ausgabe</strong> fällt der Startschuss für eine hoffentlich lange Serie eines neuen <strong>Magazin</strong>s.<br />

Einen Monat haben wir uns mit der Planung beschäftigt und an Artikeln gearbeitet, um Ihnen<br />

möglichst viele Informationen rund um die Acknex6 Engine zu vermitteln. In dieser <strong>Ausgabe</strong><br />

erwarten Sie eine Menge Tutorials, Interviews mit Sebastian Leopold und Timo Stark, den<br />

Entwicklern von Sylex 3.0 und dem kommenden Realtime-Editor GameEdit sowie einem kleinem<br />

Preview zu GameGameEdit.<br />

Um die nächsten <strong>Ausgabe</strong>n noch besser und größer zu machen, hoffen wir auf Ihre Unterstützung!<br />

• Normalmaps für Computerspiele erstellen<br />

• Vektoren<br />

• Mit Bleifuß zur Physik Engine – Part I<br />

• Viel Rauch um nichts. Ein Nebeltutorial<br />

• Modelldesign - Teil 1: Ein Tisch mit Blender<br />

• Laser - und Photonentorpedoeffekte<br />

• Bitoperatoren<br />

• Möglichkeiten des Physiksystems in Gamestudio Commercial<br />

• Formationsanordnungen in einem <strong>3D</strong> Spiel<br />

• Interview mit Sebastian Leopold (Xexes) über Sylex 3.0<br />

• Interview mit Martin (SFMAT4) und Timo (TripleX) zu ihren derzeitigen Projekten<br />

• Game-Edit<br />

Der Schwierigkeitsgrad als Anzeige<br />

In eigener Sache:<br />

Wenn Sie der Meinung sind, einen Beitrag leisten zu können, kontaktieren Sie einen der <strong>3D</strong>GS-<strong>Magazin</strong><br />

Autoren. Oder über das Forum welches auch über http://3dgsmag.ma-pre.de/forum zu erreichen ist.<br />

Das <strong>3D</strong>GS-MAGAZIN Team<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │2


Grundlagen<br />

Normalmaps für Computerspiele erstellen<br />

von Frank Geppert<br />

Eine Normalmap ist eine Textur, die zusätzlich zu der farbliefernden Textur (Diffusemap) weitere<br />

Informationen liefert. Diese Informationen geben dem Shaderprogramm der Grafikkarte an, aus<br />

welcher Richtung bestimmte Pixel beleuchtet werden sollen. Damit lassen sich räumliche<br />

Oberflächen simulieren, wo eigentlich keine Geometrie räumliche Informationen liefert.<br />

Sehen Sie dazu folgendes Beispiel. Ich habe einen einfachen Würfel erstellt, der nur mit einer<br />

einzigen Farbe texturiert ist und eine Normalmap erhält. Diese Normalmap soll eine Seite des<br />

Würfels so anzeigen, als würde eine Vertiefung auf dieser existieren und eine andere Seite soll so<br />

beleuchtet werden, als würde eine etwas herausstehende Fläche auf ihr existieren.<br />

Um dieses Ziel zu erreichen, muss man eine Normalmap erstellen, die wie folgt aussehen könnte:<br />

2 von den 6 Seiten des Würfels haben zusätzliche Informationen erhalten. Die anderen blieben in<br />

diesem Beispiel flach. Sie sehen, dass z.B. die etwas helleren Teile der Normalmap dafür sorgen,<br />

dass unser Würfel von unten beleuchtet erscheint und die dunkelblauen Streifen lassen den Würfel<br />

von oben beleuchtet erscheinen. Analog dazu gibt es Informationen für die Beleuchtung von den<br />

jeweiligen Seiten, je nachdem wie die Werte im RGB-Kanal verteilt sind.<br />

Mit dieser Methode lässt sich beliebige Geometrie vortäuschen, wo gar keine Geometrie ist. Ein viel<br />

beeindruckenderes Beispiel dazu sehen Sie weiter unten.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │3


Erstellen von Normalmaps aus Texturen<br />

Normalmaps lassen sich auf verschiedene Weise erstellen. Eine Methode ist es, diese in einem<br />

Grafikprogramm zu zeichnen. Photoshop und GIMP haben zudem jeweils Plugins, mit denen man<br />

Normalmaps aus Grafiken berechnen lassen kann. Diese Methode geht sehr einfach und schnell,<br />

führt aber nicht immer zu den gewünschten Ergebnissen.<br />

1. Ich werde dazu ein kurzes Beispiel zeigen, wie man solche Texturen in dem<br />

Grafikprogramm “The GIMP” erstellen kann. Dazu benötigen Sie ein Normalmap-Plugin für<br />

diese Software.<br />

2. Das Plugin ist schnell mit der Internetsuche und den Begriffen “Normalmap GIMP Plugin”<br />

gefunden und mit Hilfe der Anleitung installiert.<br />

3. Nach der Installation finden Sie unter Filter / Abbilden / Normalmap dieses Plugin Das<br />

Plugin präsentiert sich wie folgt:<br />

4. Wählen Sie ihren Filter und ändern Sie bei Bedarf die Parameter. Ich persönlich mag den<br />

“Sobel” Filter am meisten, da dort die Struktur am besten herausgefiltert wird.<br />

Schauen Sie sich bei Bedarf den <strong>3D</strong> Preview mit dem Schalter unter dem Vorschaufenster an.<br />

Dieses <strong>3D</strong>-Bild gibt einen ersten Eindruck, wie der Effekt im Spiel aussehen könnte. Dabei ist es<br />

sogar möglich, eine weitere Textur, die in GIMP geöffnet sein muss über dieses <strong>3D</strong>-Objekt zu<br />

überlagern. So könnten Sie prüfen, wie der Effekt mit der Diffusemap und der Normalmap<br />

aussehen könnte. Allerdings sieht man die Struktur besser, wenn man zum Testen erst einmal eine<br />

Farbtextur weglässt.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │4


Meine Erfahrungen mit diesem Tool zeigen, dass sich Graustufen- und Bumpmap-Grafiken besser<br />

eignen, als reine Farbgrafiken, um daraus Normalmaps zu generieren. Das Ergebnis zeigt<br />

tatsächlich eine interessante Struktur, die man bereits im <strong>3D</strong>-Preview-Fenster bestaunen kann.<br />

Allerdings sind extreme Tiefen und Höhen sowie eine Verfeinerung der Geometrie damit nicht<br />

realisierbar. Dafür empfehle ich das aufwändigere aber leistungsstärkere Verfahren, dass ich<br />

anschließend erklären werde.<br />

Erstellen von Normalmaps aus Geometrie<br />

Sie haben einen Spiele-Charakter, der in sehr detaillierter Form vorliegt (z.B. mehr als 200.000<br />

Polygone). Allerdings verlangt eine Spiele-Engine ein lowpoly-Modell mit z.B. 3000 Polygonen. Mit<br />

der Normalmapping-Technik können Sie ein Brücke zwischen diesen beiden Welten schlagen. Die<br />

Vorgehensweise ist dabei wie folgt:<br />

Sie erstellen ein Highpoly und ein Lowpoly Modell. Lassen Sie eine Normalmap aus dem Highpoly-<br />

Modell berechnen (Melody von nVidia, Lightwave oder <strong>3D</strong>smax) wenden Sie diese Normalmap auf<br />

das Lowpoly-Modell an.<br />

Hier sehen Sie ein Beispiel. Ich habe eine beliebiges Modell, das mit Lightwave geliefert wurde,<br />

geladen. Dieses Modell bestand aus ca. 4.000 Polygonen, die ein Subpatch-Modell von fast 50.000<br />

Polygonen lieferten. Nachfolgend sehen Sie links das Original Modell (high poly), in der Mitte das<br />

dazugehörige lowpoly Modell und anschließend das gleiche lowpoly Modell mit der Normalmap.<br />

Sie werden vermutlich den Unterschied zwischen der highpoly Figur und der lowpoly Figur mit der<br />

Normalmap nur an den Umrissen festmachen können (z.B. die eckige Wade), denn die Beleuchtung<br />

erfolgt wie bei dem Original, auch wenn die Geometrie viel weniger Details enthält. Diese Technik<br />

ist auf die beliebigsten Modelle anwendbar und ermöglicht viel detailliertere Welten, wie viele von<br />

Ihnen vielleicht schon in den Spielen “Doom3, Riddick oder F.E.A.R” sehen konnten.<br />

Ein weiterer Vorteil von Normalmaps ist, dass diese Technik nicht nur mit weniger Details in der<br />

Geometrie auskommt, sondern teilweise auch mit recht kleinen Texturen noch beeindruckend<br />

aussieht. Das liegt daran, dass viele zusätzliche Informationen durch die Beleuchtung und die<br />

Specularity-Effekte hinzukommen. Damit erhöht sich der Detailgrad allein durch die Funktionen des<br />

Shaderprogrammes mehr, als man vielleicht durch eine detaillierte Textur hinzufügen könnte.<br />

Zusätzlich besitzen einige Shader-Programme die Fähigkeit, über den Alpha-Channel der Diffuse-<br />

Map die Specularity verschiedener Bereiche der Grafik zu steuern.<br />

Ich hoffe, dass ich Ihnen einen ersten Einblick in die Arbeit mit Normalmapping liefern konnte.<br />

Wenn es weitere Fragen zu dem Thema gibt, bin ich ich unter info@geppert-software.de zu<br />

erreichen.<br />

Frank Geppert<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │5


Hallo<br />

Vektoren<br />

von Timo Stark aka Triple-X<br />

In diesem Tutorial werde ich auf Vektoren eingehen. Vektoren werden in der <strong>3D</strong> Grafik sehr häufig<br />

gebraucht, werden aber leider meistens, gerade von Anfängern, nicht verstanden. Aus diesem<br />

Grund werde ich in diesem Tutorial darauf eingehen, was Vektoren überhaupt sind, was Sie für<br />

eine Rolle in der Grafikprogrammierung spielen, wie man mit ihnen rechnet und welche<br />

Vektorbefehle es in <strong>3D</strong> Gamestudio gibt.<br />

Für dieses Tutorial sollten Sie etwas Mathematische Kenntnisse mitbringen. Erfahrungen in C-Script<br />

sind nicht nötig, da in diesem Tutorial, außer im letzten Kapitel, nicht auf C-Script eingegangen<br />

wird. Falls Sie ein Tutorial für C-Script suchen, empfehle ich Ihnen das Handbuch oder mein C-<br />

Script Tutorial für Anfänger erreichbar unter: http://www.hawkgames.de/Tutorial.php<br />

Viel Spaß beim lesen, TripleX<br />

Was sind Vektoren?<br />

Nun was sind Vektoren? Ganz allgemein gesagt, ist ein Vektor eine Ansammlung von Werten. Wie<br />

viele Werte einen Vektor bilden hängt von der Anzahl der Dimensionen ab. In einem ndimensionalen<br />

Raum hat ein Vektor n Werte. Jeden dieser Werte nennt man Vektorkomponente.<br />

Grundsätzlich können Vektoren viele Daten darstellen. Es hängt immer nur von der Interpretation<br />

des Vektors ab.<br />

Als Beispiele:<br />

1) Positionsvektor (Drei Dimensionen: X/Y/Z Koordinate)<br />

2) Richtungsvektor (Drei Dimensionen: Pan/Tilt/Roll Winkel)<br />

3) Farbvektor (Drei Dimensionen: Rot/Grün/Blau)<br />

Positionsvektoren<br />

Ein Positionsvektor beschreibt immer eine Position in einem n-dimensionalen Koordinatensystem.<br />

In <strong>3D</strong> Gamestudio werden sowohl 3-Dimensionale Vektoren zur Beschreibung von Welt-<br />

Koordinaten als auch 2-Dimensionale Vektoren zur Beschreibung von Bildschirm-Koordinaten<br />

genutzt. Nun was ist überhaupt ein Koordinatensystem und eine Koordinate? In der<br />

Grafikprogrammierung wird größtenteils mit den kartesischen Koordinatensystem gearbeitet. Im<br />

folgenden Bild sehen Sie ein Beispiel für das 3-dimensionale kartesische Koordinatensystem:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │6


Diese Grafik zeigt das normale kartesische Koordinatensystem. Zu beachten ist, dass in <strong>3D</strong><br />

Gamestudio die Y und die Z Achse vertauscht sind. Die Y Achse geht also in die Tiefe und die Z<br />

Achse nach oben.<br />

Für dieses Koordinatensystem wird eine Einheit festlegt (in <strong>3D</strong> Gamestudio ist das 1 Quant). Nun<br />

lassen sich bestimmte Positionen mit Hilfe von Positionsvektoren treffend beschreiben. Zum<br />

Beispiel der Punkt (0 | 2 | 5) (Schreibweise eines Vektors: ( X-Komponente, Y-Komponente, Z-<br />

Komponente )) liegt 5 Einheiten an der Z Achse und 2 Einheiten an der Y Achse entlang. Also<br />

diagonal nach oben in die Tiefe.<br />

Zu beachten ist, dass jedes <strong>3D</strong>-Objekt sein eigenes relatives Koordinatensystem bildet.<br />

Beispiel: Ein Haus befindet sich auf der absoluten Position (10 | 20 | 10). Ein Mensch hat die<br />

Position (5 | 20 | 30). Vom Menschen aus gesehen besitzt das Haus also die Position (5 | 0 | 20).<br />

Der Mensch bildet also ein eigenes relatives Koordinatensystem mit den Ursprung (5 | 20 | 30).<br />

Die Achsenrichtung und Ursprungsposition stimmen also nicht mit der Achsenrichtung und der<br />

Ursprungsposition des absoluten Koordinatensystems überein.<br />

Richtungsvektoren<br />

Formal (also von der Schreibweise her) unterscheiden sich Richtungsvektoren nicht von<br />

Positionsvektoren. Sie werden nur anderes interpretiert. Genau wie bei Positionsvektoren, richtet<br />

sich die Anzahl der Vektorkomponenten nach der Anzahl der Dimensionen. Zur besseren<br />

Vorstellung: In einem 2-Dimensionalen Raum brauchen Sie 2 Werte um eine Richtung zu<br />

bestimmen, in einem 3-Dimensionalen 3 Werte und so weiter. Also braucht man n<br />

Vektorkomponenten für n Dimensionen.<br />

Jede Vektorkomponente in einem Richtungsvektor besitzt normalerweise nur Werte zwischen 0 und<br />

1. Das heißt er besitzt maximal die Länge 1.<br />

Beispiel: Ein Hund besitzt die Position (10 | 0 | 0). Vom Nullpunkt ausgesehen besitzt der Hund<br />

also die Richtung (1 | 0 | 0).<br />

Sehr oft werden Richtungsvektoren auch zur Bestimmung einer Bewegungsrichtung genutzt, wobei<br />

zu beachten ist, dass bei Bewegungsvektoren auch noch die Geschwindigkeit des jeweiligen<br />

Objektes mit einbezogen wird.<br />

Beispiel: Ein Mann bewegt sich mit der Geschwindigkeit (7 | 0 | 0). Er bewegt sich also mit 7<br />

Einheiten pro Sekunde an der X Achse entlang. Setzt man nun statt (7 | 0 | 0), (1 | 0 | 0),<br />

verändert sich nicht die Richtung, sondern nur die Geschwindigkeit mit der sich der Mann bewegt<br />

(jetzt nur noch eine Einheit pro Sekunde).<br />

Rechnen von Vektoren<br />

Im folgenden werde ich auf das Rechnen mit Vektoren eingehen. Grundsätzlich kann man mit<br />

Vektoren genauso rechnen wie mit Skalaren (reelle Zahl), bis auf wenige Ausnahmen.<br />

Vektor-Addition und -Subtraktion<br />

Addition und Subtraktion mit Vektoren funktioniert genauso wie Addition und Subtraktion bei<br />

normalen reellen Zahlen.<br />

Beispiel: A und B sind Vektoren.<br />

a + b = (xa + xb | ya + yb | za + zb)<br />

a - b = (xa - xb | ya - yb | za - zb)<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │7


Zur Addition und Subtraktion von Vektoren müssen sie also legendlich alle Vektorkomponenten<br />

miteinander addieren/subtrahieren.<br />

Addition und Subtraktion von Vektoren wird sehr oft zum Bewegen von Objekten benötigt. Ein<br />

weiteres Beispiel: Eine Pflanze soll zu der Position (-10 | 23 | 10) der Vektor (0 | 7 | 2) addiert<br />

werden. Die neu berechnete Position der Pflanze ist: (-10 | 30 | 8).<br />

Der entsprechende Befehl in C-Script ist vec_add(vector1,vector2); und vec_sub(vector1,vector2);<br />

Auf Vektorbefehle wird im weiteren genauer eingegangen.<br />

Vektor Multiplikation und Division<br />

Bei der Multiplikation und der Division von Vektoren kann man zwischen zwei Arten unterscheiden<br />

1) Multiplikation / Division eines Vektors mit einer reellen Zahl (Skalar).<br />

2) Multiplikation / Division eines Vektors mit einem anderen Vektor.<br />

Vektor Multiplikation und Division mit reellen Zahlen<br />

Die Multiplikation/Division eines Vektors mit einer reellen Zahl ist sehr einfach zu verstehen. Bei<br />

einer solchen Rechnung wird einfach jede Vektorkomponente mit dem Skalaren multipliziert.<br />

Beispiel A = Vektor, s = Reelle Zahl<br />

A * s = (xa * s | ya * s | za * s)<br />

A / s = (xa / s | ya / s | za / s)<br />

Durch die Multiplikation/Division eines Vektors mit einem Skalar ist es möglich die Länge eines<br />

Vektors zu stauchen bzw. sie zu erhöhen. Dies ist z.B. sehr nützlich bei Bewegungsvektoren<br />

(erhöhen/verringern der Geschwindigkeit). Bei der Multiplikation eines Richtungsvektors mit einem<br />

Skalar bleibt die eigentliche Richtung bestehen.<br />

Als Veranschaulichung: A = Vektor der Länge 1<br />

Vektor A * 1<br />

--------------------><br />

Vektor A * 2<br />

-----------------------------------------><br />

Vektor A * 0.5<br />

----------><br />

In <strong>3D</strong> Gamestudio übernimmt vec_scale(Vektor,Zahl); diese Funktion.<br />

Vektor Multiplikation und Division mit einem Vektor<br />

Grundsätzlich kann man Vektoren auf mehrere Arten miteinander multiplizieren/teilen:<br />

1. Komponentenweise Multiplikation/Division zweier Vektoren.<br />

2. Das Kreuzprodukt<br />

3. Das Punktprodukt<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │8


Komponentenweise Multiplikation/Division zweier Vektoren<br />

Das Komponentenweise multiplizieren und teilen zweier Vektoren funktioniert, wie Sie sich<br />

wahrscheinlich schon denken genauso wie das addieren und subtrahieren zweier Vektoren.<br />

a * b = (xa * xb | ya * yb | za * zb)<br />

a / b = (xa / xb | ya / yb | za / zb)<br />

Diese Möglichkeit der Multiplikation ist in der Grafikprogrammierung allerdings kaum notwendig.<br />

Trotzdem ein Beispiel:<br />

Die Höhe (Y Achse) eines Menschen (10 | -10 | 5) soll vierfach erhöht werden. Dafür wird die<br />

aktuelle Position des Menschen mit dem Vektor (1 | 4 | 1) multipliziert.<br />

a * b = (xa * xb | ya * yb | za * zb) ---><br />

(10 | -10 | 5) * (1 | 4 | 1) = (10 * 1 | -10 * 4 | 5 * 1) = (10 | -40 | 5)<br />

Vergessen Sie nicht, dass wenn sich die Position bei einer Multiplikation nicht verändern soll, in der<br />

Vektorkomponente eins stehen muss und nicht null (0 * Zahl = 0).<br />

Das Kreuzprodukt<br />

Neben der Komponentenweise Multiplikation eines Vektors gibt es auch noch die Möglichkeit des<br />

Kreuzproduktes. In der Mathematik wird dieses Kreuzprodukt nicht über das "Mal Zeichen" sondern<br />

über das Multiplikationskreuz "x" angegeben.<br />

Im folgenden Beispiel sind A und B wie immer Vektoren (hier Richtungsvektoren).<br />

a x b = ((ya * zb) - (za * yb) | (za * xb) - (xa * zb) | (xa * yb) - (ya * xb))<br />

Diese, zugegebenermaßen, komplizierte Rechnung hat bei Richtungsvektoren den Sinn, dass der<br />

neu errechnete Vektor senkrecht auf den beiden anderen Vektoren steht. Dies funktioniert<br />

natürlich nur bei Richtungsvektoren. Ein Vektor kann unmöglich auf einen Positionsvektor<br />

senkrecht stehen (wo ist denn auf einen Punkt senkrecht).<br />

Folgendes Bild zur Veranschaulichung:<br />

B = Erster Vektor<br />

A = Zweiter Vektor<br />

Blauer / Hellgrüner Vektor = (Umgekehrter) Ergebnisvektor -> Steht Senkrecht auf B und A.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │9


Das Punktprodukt<br />

Nun die letzte Möglichkeit des multiplizieren / teilen zweier Vektoren. Das Punktprodukt. Das<br />

besondere an dem Punktprodukt ist, dass das Ergebnis kein dritter Vektor sondern eine Zahl ist.<br />

Der Sinn des Punktproduktes ist es, den Winkel zwischen zwei Richtungsvektoren zu bestimmen.<br />

a * b = (xa * xb) + (ya * yb) + (za * zb)<br />

Das Punktprodukt funktioniert nur mit normalisierten Richtungsvektoren. Das heißt es funktioniert<br />

nur mit Richtungsvektoren der Länge 0 bis 1. Auf normalisierte Vektoren werde ich später noch<br />

gesondert eingehen.<br />

Das Ergebnis dieses Punktproduktes ist der Kosinus des Winkels der von den beiden<br />

Richtungsvektoren eingeschlossen ist. Beeindruckend oder?<br />

Aus dem Kosinus eines Winkels können sie mit Hilfe der acos(Kosinus); ganz einfach einen<br />

"echten" Winkel berechnen.<br />

In <strong>3D</strong> Gamestudio übernimmt vec_dot(Vektor1,Vektor2); diese Funktion.<br />

Die Länge eines Vektors<br />

Als erstes muss definiert werden was die Länge eines Vektors überhaupt ist. Grundsätzlich ist<br />

wichtig zu sagen, dass die Länge eines Vektors nur bei einem Richtungsvektor Sinn macht. Welche<br />

Länge sollte auch eine Position haben?<br />

Was genau die Länge eines Vektors ist, kann man am besten mit Hilfe eines Beispiels erklären.<br />

Ein Mensch bewegt sich mit der Geschwindigkeit (2 | 4 | 3). Also um 2 Quants/sec an der X Achse,<br />

4 Quants/sec an der Y Achse und 3 Quants/sec an der Z Achse. Um wie viel sich der Mensch jetzt<br />

insgesamt bewegt gibt die Länge des Vektors wieder.<br />

Die Länge des Vektors kann man mit Hilfe des Satzes von Pythagoras berechnen.<br />

Um die Vektorlänge besser zu verstehen, wenden wir den Satz des Pythagoras als Erstes im 2-<br />

Dimensionalen Raum an. Der hier gezeigte Vektor besitzt die Position (C | Schnittpunkt der roten<br />

Linie mit C). Die Vektorlänge ist A (die rote Linie). Die Punkte (0 | 0), (C | Schnittpunkt der<br />

roten Linie mit C) und (C | 0) bilden ein rechtwinkliges Dreieck. Daher ist der Einsatz des Satz des<br />

Pythagoras möglich.<br />

Also ist die Länge eines 2-Dimensionalen Vektors:<br />

L = Wurzel(xa² + ya²)<br />

Wie sie vermutlich schon selber folgern können ist also die Formel für die Berechnung der Länge<br />

eines Vektors im 3-Dimensionalen Raum:<br />

L = Wurzel(xa² + ya² + za²)<br />

Diese Funktion übernimmt vec_length(Vektor); in C-Script für Sie.<br />

Dadurch, dass Sie jetzt wissen wie man die Länge eines Vektors berechnet, können Sie auch die<br />

Distanz zwischen zwei Punkten berechnen. Wie geht das werden Sie sich vielleicht fragen. Nun<br />

ganz einfach. Sie bilden durch die Subtraktion des 1. Vektors von den 2. Vektor einen<br />

"Verbindungsvektor". Jetzt berechnen Sie die Länge des Vektors. Dies ist die Distanz zwischen den<br />

beiden Positionsvektoren.<br />

Ein Beispiel indem Sie die Entfernung auch ohne Berechnung sehen würden, damit Sie es glauben<br />

Eine Frau an der Position (10 | 50 | 50) würde gerne Ihre Entfernung zu den Flugzeug (10 | 1000 |<br />

50) wissen. Wie kann sie diese Entfernung berechnen?<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │10


Zuerst der Verbindungsvektor V:<br />

V = A - B<br />

V = (10 | 50 | 50) - (10 | 1000 | 50)<br />

V = (0 | -950 | 0)<br />

Jetzt wird also noch die Länge dieses neu errechneten Vektors bestimmt:<br />

L = Wurzel(xv² + yv² + zv²)<br />

L = Wurzel(0 * 0 + -950 * - 950 + 0 * 0)<br />

L = Wurzel(902500);<br />

L = 950;<br />

Die Distanz beträgt also 950 Quants, wie Sie zweifellos sofort gesehen haben ;-) Da dieses Beispiel<br />

sehr einfach war rechnen Sie es am besten noch mal mit der Position Frau = (0 | 2 | -30) und<br />

Flugzeug = (620 | 1200 | 2) aus. Hier sehen Sie die Distanz nicht auf den 1. Blick. Sie sollten<br />

ungefähr auf das Ergebnis 1343 kommen. In C-Script übernimmt übrigens die Funktion<br />

vec_dist(vector1,vector2); diese Aufgabe.<br />

Vektoren in <strong>3D</strong>-Gamestudio und C-Script<br />

Das schwierigste haben Sie jetzt hinter sich gebracht. Nun kommt der praktische Teil dieses<br />

Tutorials der sich mit der Frage beschäftigt, wie man Vektoren in C-Script benutzen kann.<br />

Definieren von Vektoren<br />

In <strong>3D</strong>-Gamestudio haben Vektoren immer 3-Vektorkomponenten. Dies liegt einfach daran, dass<br />

wie der Name von <strong>3D</strong>-Gamestudio schon sagt, mit einem Vektor ein 3-Dimensionaler Raum<br />

beschrieben wird. Definieren kann man den Vektor über das var Keyword.<br />

Var Vektorname[3];<br />

Der Name ist beliebig. Ich würde allerdings empfehlen, damit Vektoren auch als solche erkenntlich<br />

sind, den Namen mit einem bestimmten Prä oder Suffix (_vec o.ä.) versehen. Falls der Vektor<br />

einen vordefinierten Wert haben soll geht dies über folgende Definierung:<br />

Var Vektorname[3] = Wert X, Wert Y, Wert Z;<br />

Vektoren können auch in Funktionen, also lokal, definiert werden. Auf eine Vektorkomponente<br />

kann mit folgenden Werten zugegriffen werden:<br />

Vektorname[0] = Wert; //Greift auf den X Wert zu<br />

Vektorname[1] = Wert; //Greift auf den Y Wert zu<br />

Vektorname[2] = Wert; //Greift auf den Z Wert zu<br />

Vektorname.x = Wert; //Greift auf den X Wert zu<br />

Vektorname.y = Wert; //Greift auf den Y Wert zu<br />

Vektorname.z = Wert; //Greift auf den Z Wert zu<br />

Vektorname.pan = Wert; //Greift auf den X Wert zu<br />

Vektorname.tilt = Wert; //Greift auf den Y Wert zu<br />

Vektorname.roll = Wert; //Greift auf den Z Wert zu<br />

Vektorname.blue = Wert; //Greift auf den X Wert zu<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │11


Vektorname.green = Wert; //Greift auf den Y Wert zu<br />

Vektorname.red = Wert; //Greift auf den Z Wert zu<br />

Wie Sie sehen macht es C-Script Ihnen sehr einfach auf Vektoren zuzugreifen. Wichtig ist, dass es<br />

keinen Unterschied macht ob Sie<br />

Oder<br />

Vektorname.blue = 128;<br />

Vektorname[0] = 128;<br />

schreiben. Es ist nur einfacher für den Programmierer (also Sie) zu verstehen wie dieser Vektor<br />

interpretiert wird.<br />

Wichtig ist, dass bei lokal definierten Vektoren nur der 1. Interpretationsweg (also über<br />

[0]/[1]/[2]) als richtig anerkannt wird.<br />

X/Y/Z wird bei Positionsvektoren, Pan/Tilt/Roll bei Richtungsvektoren und Blue/Green/Red bei<br />

Farbvektoren genutzt.<br />

Besonderheiten von Vektoren in <strong>3D</strong>-Gamestudio<br />

Folgende Besonderheiten sind bei Vektoren in <strong>3D</strong>-Gamestudio zu beachten:<br />

1) Die Y und die Z Achse sind im Koordinatensystem vertauscht. Das heißt, dass die Z-Achse in die<br />

Höhe und die Y Achse in die Tiefe geht.<br />

2) Mit Vektoren kann man nicht wie mit normalen reellen Zahlen rechnen. Das heißt eine direkte<br />

Zuweisung („=“), oder das einfache addieren („+“) zweier Vektoren mit einfachen Rechenzeichen<br />

ist nicht möglich. Hierzu gibt es Befehle auf die ich im folgenden eingehen werde. Sehr wohl<br />

können allerdings alle Grundrechenarten mit einzelne Vektorkomponenten ( vec1.x = vec2.x; )<br />

durchgeführt werden. Auf diesen Weg sind alle oben angegeben Vektorrechnungen auch in C-Script<br />

möglich.<br />

Vec_Set(Vektor1,Vektor2);<br />

Mit Hilfe dieses Befehls werden alle 3 Vektorkomponenten des ersten Vektors mit dem 3<br />

Vektorkomponenten des zweiten Vektors überschrieben.<br />

Beispiel:<br />

Var Vec1[3] = 10,20,30 ;<br />

Var Vec2[3] = 2,15,22 ;<br />

Vec_set(Vec1,Vec2) ; /* Die Drei Vektorkomponenten von Vec1 nach dieser Anweisung: (2 | 15 |<br />

22) */<br />

//das gleiche (nur etwas schneller) wie:<br />

Vec1.x = Vec2.x;<br />

Vec1.y = Vec2.y ;<br />

Vec1.z = Vec2.z ;<br />

Vec_Add(Vektor1,Vektor2);<br />

Mit Hilfe dieses Befehls werden alle 3 Vektorkomponenten des ersten Vektors mit dem 3<br />

Vektorkomponenten des zweiten Vektors addiert. Das Ergebnis dieser Anweisung wird in den<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │12


ersten Vektor geschrieben.<br />

Beispiel:<br />

Var Vec1[3] = 10,20,30 ;<br />

Var Vec2[3] = 2,15,22 ;<br />

Vec_add(Vec1,Vec2) ; /* Die Drei Vektorkomponenten von Vec1 nach dieser Anweisung: (12<br />

| 35 | 52) */<br />

//das gleiche (nur etwas schneller) wie:<br />

Vec1.x += Vec2.x;<br />

Vec1.y += Vec2.y ;<br />

Vec1.z += Vec2.z ;<br />

Vec_Sub(Vektor1,Vektor2);<br />

Mit Hilfe dieses Befehls werden alle 3 Vektorkomponenten des ersten Vektors mit dem 3<br />

Vektorkomponenten des zweiten Vektors subtrahiert. Das Ergebnis dieser Anweisung wird in den<br />

ersten Vektor geschrieben.<br />

Beispiel:<br />

Var Vec1[3] = 10,20,30 ;<br />

Var Vec2[3] = 2,15,22 ;<br />

Vec_add(Vec1,Vec2) ; /* Die Drei Vektorkomponenten von Vec1 nach dieser Anweisung: (8<br />

| 5 | 8) */<br />

//das gleiche (nur etwas schneller) wie:<br />

Vec1.x -= Vec2.x;<br />

Vec1.y -= Vec2.y ;<br />

Vec1.z -= Vec2.z ;<br />

Vec_Scale(Vektor1,Zahl);<br />

Mit Hilfe dieses Befehls werden alle 3 Vektorkomponenten des ersten Vektors mit der angegeben<br />

Zahl multipliziert (siehe Oben). Das Ergebnis dieser Anweisung wird in den ersten Vektor<br />

geschrieben.<br />

Beispiel:<br />

Var Vec1[3] = 10,20,30 ;<br />

Var factor = 10;<br />

Vec_add(Vec1,factor) ; /* Die Drei Vektorkomponenten von Vec1 nach dieser Anweisung:<br />

(100 | 200 | 300) */<br />

//das gleiche (nur etwas schneller) wie:<br />

Vec1.x *= factor;<br />

Vec1.y *= factor ;<br />

Vec1.z *= factor ;<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │13


Vec_Length(Vektor);<br />

Mit Hilfe von Vec_Length können sie schnell die Länge (s.o.) eines Vektors bestimmen. Die Länge<br />

eines Vektors ist in <strong>3D</strong> Gamestudio nichts anders als seine Distanz zum Nullpunkt (0 | 0 | 0, oder<br />

der vordefinierte Vektor: nullvector).<br />

Vec_Dist (Vektor1,Vektor2);<br />

Mit Hilfe von Vec_Dist können sie schnell die Entfernung zwischen zwei Vektoren (s.o.) bestimmen.<br />

Die Distanz wird von dieser Funktion zurückgegeben („Return-Value“).<br />

Vec_inverse (Vektor);<br />

Die Funktion vec_inverse kehrt den angegeben Vektor um. Das heißt, dass sie jede<br />

Vektorkomponente mit -1 multipliziert.<br />

Vec_dot(Vektor1,Vektor2);<br />

Diese Funktion liefert das Punktprodukt der beiden Vektoren zurück. Grundsätzlich macht sie<br />

genau das, was wir oben beschrieben haben.<br />

Vec_normalize (Vektor,Zahl);<br />

Diese Funktion normalisiert den angegeben Vektor. Besonders an dieser Funktion ist die<br />

angegebene Zahl. In Gegensatz zu dem mathematisch korrekten normalisieren auf eine Länge<br />

unter 1, kann der Vektor auch auf eine andere Vektorlänge (angegeben mit „Zahl“) normalisiert<br />

werden. Folgender Algorithmus wird hierbei angewandt:<br />

temp = vec_length(Vektor.x);<br />

Vektor.x = Vektor.x / temp * zahl;<br />

my.y = Vektor.y / temp * zahl;<br />

my.z =Vektor.z / temp * zahl;<br />

Vec_To_angle (Vektor Angle, Richtungsvektor);<br />

Diese erste etwas komplexere Vektor-Funktion in C-Script. Diese Funktion berechnet aus dem Wert<br />

des Richtungsvektor, den Pan/Tilt und Roll Wert und schreibt diesen in den ersten Vektor. Mit<br />

dieser Funktion kann zum Beispiel ein Entity in eine bestimmte Richtung gedreht werden.<br />

// hole die Richtung von der Entity MY zur Entity YOU<br />

vec_set(temp,your.x); //setzte Temp auf your.x<br />

vec_sub(temp,my.x); //ziehe von temp.x, my.x ab -> Bewegungsvektor entsteht<br />

vec_to_angle(my.pan,temp);// Rechne dieses Bewegungsvektor (vom Nullpunkt aus gesehen)<br />

in Richtungswinkel um und setzte die Werte in den my.pan Vektor<br />

Vielleicht ist dieser Code nicht sehr schnell zu verstehen, aber machen Sie sich am besten eine<br />

Zeichnung in einem 2-Dimensionalen Koordinatensystem zur besseren Vorstellung. Sie werden<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │14


sehen dass das Ergebnis stimmt.<br />

Vec_Rotate(Richtungsvektor, Vektor Angle);<br />

Die zweite etwas komplexere Vektor-Funktion. Diese Funktion dreht die Richtung des ersten<br />

Vektors um die Pan, Tilt und Roll Werte des zweiten Vektors. Hört sich kompliziert an, ist aber an<br />

einem Beispiel sehr einfach zu verstehen.<br />

Vec_set(temp.x,vector(50,0,0)); //setzt temp Vektor auf (50 | 0 | 0)<br />

vec_rotate(temp.x,camera.pan); //rotiert temp Vektor um Kamera Drehung<br />

vec_add(temp.x,camera.x); //addiert die Kameraposition zu dem Temp Vektor<br />

Nach dieser Anweisung ist der Vektor temp.x genau 50 Quants VOR der Kamera<br />

Vec_Cross(Vektor1,Vektor2,Vektor3);<br />

Diese Funktion ist leider nicht in C-Script vorhanden. Daher müssen wir sie auf wohl oder über<br />

selber schreiben. Folgende Funktion bildet das Kreuzprodukt aus Vektor1 und Vektor2 und schreibt<br />

das Ergebnis in Vektor3.<br />

function vec_cross(vec1,vec2,vec3)<br />

{<br />

vec_set(vec3.x,vector((vec1.y * vec2.z) - (vec1.z * vec2.y),(vec1.z * vec2.x) -<br />

(vec1.x * vec2.z),(vec1.x * vec2.y) - (vec1.y * vec2.x)));<br />

}<br />

Ich hoffe, dass dieses Tutorial Ihnen einen Einblick in die große Welt der Vektor-Mathematik gab.<br />

Falls nicht, oder falls noch Fragen offen sind, senden Sie mir bitte eine Email an<br />

TripleX@hawkgames.de .<br />

Vielen Dank für das lesen<br />

Timo Stark aka Triple-X<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │15


Mit Bleifuß zur Physik Engine – Part I<br />

von Ruben Aster aka Asse<br />

Erstellen Sie im ersten Teil dieses Workshops einen physikgesteuerten Ferrari F360 mit einigen<br />

Hindernissen.<br />

Einleitung<br />

Begrüßung<br />

Willkommen zum ersten Teil meines Workshops über eines der besten Plugins, welches z.Zt.<br />

kostenfrei für <strong>3D</strong> GameStudio erhältlich ist – Newton Game Dynamics.<br />

Viele kennen es und fast genauso viele haben Probleme es richtig einzusetzen. Daher hoffe ich,<br />

dass zum Ende dieses Tutorials einige Verwirrungen geklärt sind und Sie die Funktionsweise von<br />

Newton Game Dynamics (im weiteren NGD) besser verstanden haben. Um dies zu erreichen,<br />

werden Sie einen physikgesteuerten Ferrari F360 erstellen und diesem einige Physikobjekte in den<br />

Weg legen.<br />

Ich habe bereits ein Level und eine dazugehörige Skriptdatei angefertigt, welche nur noch<br />

bearbeitet werden muss, damit ich nicht weiter auf das Drumherum eingehen brauche.<br />

Das wird gebraucht<br />

• die Dateien vom Workshop,<br />

http://www.gfxtreme.de/files/3dgs/workshop_newton<strong>01</strong>/ngd_workshop<strong>01</strong>.zip<br />

• <strong>3D</strong> GameStudio Extra, Standart, Commercial oder Pro<br />

• Newton Game Dynamics 1.51 Plugin für <strong>3D</strong>GS<br />

• Das Plugin finden Sie auf dieser Seite (ganz unten):<br />

http://www.physicsengine.com/downloads.html<br />

Sie können dabei wählen, ob Sie nur das Plugin oder auch noch verschiedene Demos und Tutorials<br />

als Bundle runterladen möchten. Dabei empfehle ich selbst 56k Usern wie mir das 30MB Package,<br />

da wirklich einige sehr interessante Beispiele dabei sind, welche die vielfältigen Möglichkeiten von<br />

NGD demonstrieren.<br />

Kurze Erklärung<br />

Da wir uns hier im ersten Teil - also sozusagen der Vorbereitung - befinden, wird das Skripten mit<br />

NGD nur oberflächlich behandelt. Sie werden die meisten Physik-Werte, ähnliche wie bei den <strong>3D</strong>GS<br />

Templates, direkt in WED setzen. Uninteressant wird es jedoch trotzdem nicht werden, denn das<br />

NGD Plugin ist in erster Linie dafür gedacht, so einfach gehandhabt zu werden.<br />

Dennoch ist es ein Vorteil dann im zweiten Teil zu lernen, wie z.Bsp. physikalische Werte gelesen<br />

werden um etwa einen Tacho für unseren Ferrari zu erstellen, ein Motorengeräusch zu erzeugen,<br />

anhand der Reifenreibung quietschende Reifen zu simulieren oder einfach nur einen<br />

überschlagenen Wagen wieder zu reseten.<br />

Also dann, geben wir Gas!<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │16


Vorbereitung<br />

Um ein komplett eigenständiges Projekt zu erstellen, müssen Sie aus Ihrem <strong>3D</strong><br />

GameStudio\template\ Ordner einige Dateien von Newton kopieren. Der Übersicht halber habe ich<br />

im Workshop-Ordner zwei Unterordner angelegt und diese schon in der newton<strong>01</strong>.wdl definiert.<br />

Kopieren Sie die Dateien wie folgt:<br />

newton.dll, newtonsplash.tga, newton.wdl, newtonScript2.wdl, newtonVehicle.wdl nach Workshop -<br />

Newton Physics P1\<br />

click.wav, door_cl.wav, door_op.wav, hit.wav nach Workshop - Newton Physics P1\sounds\<br />

Als nächstes bereiten wir unser Skript für Newton vor.<br />

Öffnen Sie die newton<strong>01</strong>.wdl und linken Sie als Erstes die wdls von Newton gleich unter dem<br />

Kommentar „// hier newton wdls linken“.<br />

include ;<br />

include ;<br />

include ;<br />

Unter dem Kommentar „// hier splashscreen und cls datei definieren“ geben Sie den folgenden<br />

Code ein, welcher den Splashscreen mit dem Newtonlogo und die Newton Hintergrund-Map<br />

definiert.<br />

bmap splashscreen = &ltnewtonsplash.tga>;<br />

string newtonLevel_cls = &ltnewton<strong>01</strong>.cls>;<br />

Die Newton-Hintergrund-Map (.cls) wird von NGD benötigt um Kollision mit der Levelgeometrie zu<br />

simulieren. Erstellt wird diese Datei automatisch beim Starten eines Levels aus WED. Wichtig ist<br />

nur, dass das Level vorher abgespeichert (nicht mit kompilieren verwechseln) wurde, damit die .cls<br />

aus der aktuellen .wmp generiert werden kann. Sollten Sie sich also mal wundern, warum Sie<br />

durch eine Mauer oder ähnliches durchfahren können, so haben Sie nach einer Änderung der<br />

Geometrie nicht gespeichert.<br />

Zu guter letzt müssen wir noch unter dem Kommentar in der main Funktion „// hier Newton Map<br />

erstellen„ die Hintergrund-Map für Newton erstellen lassen:<br />

wait(1);<br />

dll_handle = newtonHandle;<br />

NewtonAddMap(wmb_Level, splashscreen);<br />

Damit haben Sie alle Vorbereitungen abgeschlossen und können nun mit der Erstellung eines<br />

Newton-Projekts beginnen!<br />

Das Fahrzeug erstellen<br />

Skripten<br />

Ich hoffe Sie sind nicht allzu schreibfaul, denn jetzt sind erstmal ein paar Zeilen Code fällig. Doch<br />

keine Sorge, ich werde alles erklären, sodass Sie nicht im Dunkeln tappen.<br />

Definieren Sie zunächst einen Entity-Pointer, mit welchem wir später auf den Wagen zugreifen<br />

können. Falls Sie nicht wissen wo, dann suchen Sie nach dem Kommentar „// hier entity-pointer<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │17


festlegen“.<br />

entity* p_F360;<br />

Legen wir nun eine Aktion für unseren Ferrari an (die Kommentarzeilen dürfen nicht vergessen<br />

werden, Erklärung folgt später noch):<br />

// uses mass, linear_drag, angular_drag_x, angular_drag_y, angular_drag_z, health,<br />

shape_factor; // uses collision_sph_box, start_active, compound_collision,<br />

destructible, spawn_children; // uses car_topSpeed, car_maxToque; action newton_F360<br />

{<br />

var car;<br />

// weise den pointer p_F360 zu<br />

p_F360 = my;<br />

// erstelle den wagen durch newton<br />

NewtonCreateVehicle (wood_material, VehicleTireEvent, VehicleBeginEvent,<br />

VehicleEndEvent);<br />

dll_handle = newtonHandle;<br />

car = NewtonGetBody (my);<br />

// kontrolliere den wagen per skript<br />

NewtonSetBodyAutoActiveState (car, 0);<br />

NewtonSetBodyActiveState (car, 1);<br />

// setze schwerkraft<br />

NewtonSetBodyForceAndTorque (car, VehicleForceEvent);<br />

// while loop zum steuern des wagens<br />

while (1)<br />

{<br />

werden<br />

// umdrehung und reifenstellung zurücksetzen, damit die werte nicht addiert<br />

my.carEngineTorque = 0.0;<br />

my.carSteerTorque = 0.0;<br />

if(key_a)<br />

{<br />

}<br />

// volle Reifenstellung links<br />

my.carSteerTorque = 1.0;<br />

if(key_d)<br />

{<br />

// volle Reifenstellung rechts<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │18


}<br />

}<br />

}<br />

my.carSteerTorque = -1.0;<br />

if(key_w)<br />

{<br />

}<br />

// vollgas positiv<br />

my.carEngineTorque = my.car_maxToque;<br />

if(key_s)<br />

{<br />

}<br />

// halb vollgas negativ<br />

my.carEngineTorque = -my.car_maxToque * 0.5;<br />

wait(1);<br />

Über dieser Aktion legen Sie zwei Funktionen an, die Newton zum erstellen des Wagens benötigt.<br />

Mit Hilfe dieser Funktionen können z.Bsp. quietschende Reifen simuliert werden, wir werden dafür<br />

aber in Teil 2 unsere eigenen Funktionen schreiben.<br />

function VehicleBeginEvent(vehicleConst)<br />

{<br />

}<br />

var p;<br />

p = 0;<br />

function VehicleEndEvent(vehicleConst)<br />

{<br />

}<br />

var p;<br />

p = 0;<br />

Legen Sie noch eine weitere Funktion unter diesen beiden an und dann haben Sie es für’s Erste<br />

fast geschafft. Diese Funktion definiert Verhalten und Einstellungen der Reifen, sie sollte also nicht<br />

ganz uninteressant für Sie sein.<br />

function VehicleTireEvent(vehicleConst, tyreIndex)<br />

{<br />

var steer;<br />

var omega;<br />

var torque;<br />

var resistance;<br />

steer = NewtonGetTyreSteerParam (vehicleConst, tyreIndex);<br />

steer = steer + (my.carSteerTorque - steer) * 0.25;<br />

NewtonSetTyreSteerParam (vehicleConst, tyreIndex, steer);<br />

// reibung der reifen auf dem boden, je niedriger desto rutschiger<br />

NewtonSetTyreLateralFrictionCoef (vehicleConst, tyreIndex, 1);<br />

NewtonSetTyreLongituFrictionCoef (vehicleConst, tyreIndex, 1);<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │19


torque = my.carEngineTorque;<br />

if (torque != 0)<br />

{<br />

resistance = my.car_maxToque * NewtonGetTyreRadius (vehicleConst, tyreIndex) /<br />

my.car_topSpeed;<br />

}<br />

}<br />

else<br />

{<br />

}<br />

resistance = 0.15 * NewtonGetTyreInertia (vehicleConst, tyreIndex);<br />

omega = NewtonGetTyreOmega (vehicleConst, tyreIndex);<br />

torque = torque - resistance * omega;<br />

NewtonSetTyreTorque (vehicleConst, tyreIndex, torque);<br />

Und nun noch eine letzte Funktion. Mit dieser legen Sie die Schwerkraft Ihres Wagens fest.<br />

Wenn Sie einen Blick in die newtonScript2.wdl werfen und nach der Funktion<br />

ApplyGravityForceEvent(body) suchen, werden Sie schnell merken, dass<br />

NewtonBodyAddForce(body, force_x, force_y, force_z) dafür verantwortlich ist. Durch Verändern<br />

der Werte und etwas Skripten könnten Sie Ihren Ferrari z.Bsp. einfach in einen schwebenden<br />

Raketenwagen umfunktionieren.<br />

function VehicleForceEvent(body)<br />

{<br />

}<br />

ApplyGravityForceEvent(body);<br />

NewtonSetBodyAutoActiveState (body, 0);<br />

Na also, so viel war es doch gar nicht. Überlegen Sie nur wieviel Zeilen Code das NGD-Team<br />

schreiben musste damit Sie es so einfach haben. Und sollten Sie die ein oder andere Rechnung<br />

nicht verstanden haben, ist das auch nicht weiter schlimm. Die entscheidenden Einstellungen des<br />

Fahrzeugs und dessen Reifen werden gleich bequem in WED gesetzt. Speichern!<br />

Fahrzeugteile in WED ausrichten<br />

Hände von der Tastatur und WED geöffnet, jetzt wird mit der Maus gearbeitet!<br />

Laden Sie meinen vorgefertigten Raum (newton<strong>01</strong>.wmp) und fügen Sie die Karosserie des F360 in<br />

WED ein, Object -> Add Model, im Ordner models\ das Modell aut_f360.mdl. Platzieren Sie die<br />

Karosserie an einer gewünschten Stelle innerhalb des Raumes.<br />

Bevor Sie die Reifen hinzuladen noch ein Hinweis. Der Mittelpunkt der Reifen sollte genau im<br />

Zentrum liegen, ansonsten eiert es während der Fahrt. Kontrollieren Sie daher vorerst in MED, ob<br />

die Reifen an der richtigen Stelle sitzen und korrigieren Sie dies, wenn nötig.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │20


Wenn alles sitzt, laden Sie jetzt noch das Reifenmodell rue_360_d.mdl, duplizieren es dreimal und<br />

platzieren die vier Reifen, wie auf dem Screenshot zu sehen, um die Karosserie. Dabei ist es<br />

gewollt, dass die Reifen auf der linken Seite in die falsche Richtung zeigen, dies korrigiert NGD<br />

automatisch.<br />

Kleiner Tipp:<br />

Unter File -> Preferences kann man die Werte verändern um Objekte präziser bewegen (Snap) und<br />

drehen (Rotate Snap) zu können.<br />

Als nächstes gruppieren wir alle fünf Teile des Fahrzeugs. Klicken Sie dazu jeweils auf einen davon<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │21


und drücken dann die Taste G. Haben Sie diesen Vorgang für alle Teile durchgeführt, drücken Sie<br />

abschließend Strg + G. Nun sollten all Ihre Fahrzeugteile als ein Objekt vorliegen.<br />

Wählen Sie das Fahrzeug an (es sollten alle Teile rot dargestellt werden) und wählen Sie Object -><br />

Scope -> Scope down bzw. klicken Sie auf das entsprechende Icon in der Menüleiste. Was Sie jetzt<br />

vor sich haben ist ausschließlich das gruppierte Auto mit allen anwählbaren Einzelteilen. Damit<br />

Newton aber korrekt mit dieser Karosserie-Reifen-Konstruktion umgehen kann, müssen jetzt noch<br />

einmal alle vier Reifen zusammen gruppiert werden. Führen Sie dazu einfach nochmals den obigen<br />

Gruppiervorgang durch, nur diesmal ohne die Karosserie.<br />

Konfigurieren des Fahrzeugs<br />

Nun wird es richtig interessant, denn jetzt konfigurieren wir unseren Wagen, sowie die einzelnen<br />

Räder. Wer also schon immer mal einen Ferrari F360 tunen wollte, hat jetzt die Gelegenheit dazu.<br />

Scopen Sie zu der Ebene, in der man die Karosserie einzeln anwählen kann, rechtsklicken Sie<br />

darauf, wählen Properties und im aufpoppenden Dialog wählen Sie den Tab „behaviour“. Rechts<br />

neben dem Eingabefeld für die Aktion klicken Sie auf den offenen Ordner (Choose Action) und<br />

wählen aus der Liste Ihre vorhin erstellte Aktion „newton_F360“.<br />

Hier können Sie nun, wie versprochen, so gut wie alles einstellen was das Herz begehrt. Noch<br />

interessanter sind gleich die Reifeneinstellungen, wir gehen aber erstmal die wichtigsten Werte für<br />

die Karosserie durch. Meine empfohlenen Werte stehen dabei immer in Klammern gleich hinter der<br />

Bezeichnung.<br />

• Mass (130) – Gibt das Gewicht der Karosserie an. Wichtiger Faktor, wenn es darum geht<br />

mit anderen Physikobjekten zu kollidieren. Zudem liegt das Fahrzeug tiefer und schwerer<br />

auf der Strasse, je höher dieser Wert ist.<br />

• Linear_drag und Angular_drag (0.1) – Mit diesen Werten kann man Luftwiderstände<br />

simulieren. Setzen Sie hier einfach überall 0.1 ein.<br />

• Health (0) – Dieser Wert funktioniert in Verbindung mit Destructible und Spawn_children.<br />

Je höher der Wert, desto mehr Schaden hält das Objekt stand.<br />

• Shape_factor (0) – Schwer zu erklären und ich hoffe ich hab es richtig verstanden (immer<br />

wird einem alles auf englisch erklärt :-/ ). Jedenfalls ist die Kollisionsbox eines Objekts vom<br />

Volumen her natürlich größer als das Objekt selber und das Prinzip des Archimedes besagt,<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │22


dass die Schwerkraft eines Körpers auf Wasser gleich dem Gewicht des vom Körper<br />

verdrängten Wassers ist. Nun da die Kollisionsbox größer ist als das Objekt, wird zu viel<br />

Wasser verdrängt und das Objekt sinkt dementsprechend natürlich tiefer. Abhilfe schafft<br />

hier der Wert shape_factor, welcher das Volumen der Kollisionsbox multipliziert und somit<br />

verkleinert. Idealer Weise natürlich auf die Größe des Objekts. Nicht verstand? Auch nicht<br />

weiter schlimm, Sie werden den Wert kaum brauchen.<br />

• Car_topspeed (1500) – Ganz einfach die Höchstgeschwindigkeit des Wagens.<br />

• Car_maxtorque (50) – Gibt an, wie schnell der Wagen beschleunigt.<br />

• Collision_sph_box (unchecked) – Wenn aktiviert, wird eine Kugel zur Kollisionserkennung<br />

benutzt, ansonsten eine Box.<br />

• Start_active (checked) – Wenn aktiviert, fällt, rollt und bewegt sich dieses Objekt falls es<br />

die Lage erfordert, ansonsten reagiert das Objekt erst auf Physik, wenn es von einem<br />

anderen Physikobjekt getroffen wurde.<br />

• Compound_collision (unchecked) – Bei zusammengesetzten Objekten wird jedes einzelne<br />

Teil als Kollisionsbox verwendet. Achtung, keine Gewähr für die Richtigkeit dieser<br />

Beschreibung!<br />

• Destructible (unchecked) – Ist dieses Flag gesetzt, so ist das Objekt anfällig gegen<br />

Schaden und der oben angegebene Health-Wert verringert sich bei jeder Kollision mit einem<br />

anderen Physikobjekt.<br />

• Spawn_children (unchecked) – Erreicht der Health-Wert 0, so wird das Objekt zerstört<br />

und durch seine Child-Objekte ersetzt (z.Bsp. einem Wrack unseres Wagens).<br />

Haben Sie alle Werte gesetzt, sind nun die Reifen an der Reihe. Scopen Sie bis zur untersten<br />

Ebene, in der Sie jedes Rad einzeln anwählen können und weisen Sie jedem Rad die Aktion<br />

„NewtonVehicleTyre“ zu.<br />

Bevor Sie die Werte für jedes Rat setzen, lesen Sie sich erstmal deren Bedeutung durch, bei Reifen<br />

ist es nämlich ein klein wenig komplizierter.<br />

• Mass (2) – Wie bei der Karosserie gibt dieser Wert das Gewicht an.<br />

• Steer_angle (hinten 0, vorne 20) – Gibt an, um wieviel Grad sich die Räder einlenken<br />

lassen. Bei herkömmlichen Wagen sollten Sie für die Hinterreifen 0 eingeben, da diese sich<br />

normalerweise nicht lenken lassen.<br />

• Suspension_span (10) – Die Länge der Aufhängung.<br />

• Suspension_dashpot (1.2) – Gibt die Stärke des Stoßdämpfers der Aufhängung an. Ist<br />

dieser Wert zu niedrig, wird Ihr Wagen hin und her hopsen.<br />

• Suspension_stiffness (5) – Gibt die Straffheit der Aufhängung an. Je höher der Wert,<br />

desto härter liegt der Wagen auf der Strasse.<br />

• Rolling_dry_friction (0.5) – Gibt an, wie stark der Wagen in der Kurve schlittert – nicht<br />

übertreiben!<br />

• Is_leftwheel – Muss markiert werden, wenn es sich um einen linken Reifen des Wagens<br />

handelt.<br />

• Is_poweredwheel – Gibt an, ob das Rad angetrieben wird oder nicht. Soweit ich weiß,<br />

wird z.Zt. sowieso nur Allrad unterstützt, somit kann man diese Checkbox leer lassen.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │23


Nun, da Sie wissen, dass man linke Reifen definieren muss und die Hinterreifen einen<br />

Einlenkwinkel von 0 Grad haben sollten, können Sie Ihre Werte eintragen.<br />

Sind Sie damit fertig, schauen Sie nochmal kurz ob sich das Modell auch innerhalb des Raumes<br />

befindet…<br />

…, speichern und kompilieren das Level und starten es anschließend.<br />

Wenn Ihnen keine Fehlermeldungen in den Weg kamen, sollten Sie Ihren Wagen von oben auf der<br />

Strecke sehen und Ihn mit W-A-S-D steuern können. Zusätzlich können Sie noch mit dem<br />

mittleren Mausrad zoomen und mit gedrückter rechter Maustaste die Kamera um das Auto<br />

bewegen.<br />

Zusätzliche Physikobjekte plazieren<br />

Kurze Erklärung<br />

NGD hat schon einige vorgefertigte Materialien, welche Gegenständen zugeordnet werden können,<br />

um Physik zu simulieren. Da wir aber noch etwas Zeit (und sicher auch Lust haben ;) und einige<br />

wichtige Materialeigenschaften nur per Skript gesetzt werden können, werden wir unser eigenes<br />

Material erstellen.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │24


Öffnen Sie die newtonScript2.wdl und scrollen Sie zur Funktion NewtonSetupSystem(). In dieser<br />

Funktion werden die verschiedenen Materialien erstellt und die Eigenschaften untereinander<br />

definiert.<br />

Um dies zu erklären, stelle ich kurz die Definition für die Eigenschaften zwischen Ground und Wood<br />

Material vor.<br />

// set material interaction propeteries (ground_material, wood_material)<br />

NewtonMaterialSetFriction (ground_material, wood_material, 1.0, 0.7);<br />

NewtonMaterialSetElasticity (ground_material, wood_material, 0.4);<br />

NewtonMaterialSetDepthRecover (ground_material, wood_material, 0.2);<br />

NewtonMaterialSetSoundEffect (ground_material, wood_material, hit);<br />

Wie man anhand der Kommentarzeile richtig vermuten darf, wird hier festgelegt, wie Gegenstände,<br />

welchen die Aktion NewtonWoodEntity zugewiesen wurde, sich beim Zusammenprall mit der<br />

Levelgeometrie (ground_material) verhalten.<br />

Würden wir hingegen diese Zeilen schreiben…<br />

NewtonMaterialSetFriction (ice_material, wood_material, 1.0, 0.7);<br />

NewtonMaterialSetElasticity (ice_material, wood_material, 0.4);<br />

NewtonMaterialSetDepthRecover (ice_material, wood_material, 0.2);<br />

NewtonMaterialSetSoundEffect (ice_material, wood_material, hit);<br />

…würden wir definieren, wie sich Ice Material beim Zusammenprall mit dem Wood Material<br />

verhalten soll.<br />

Eine Liste von allen zuweisbaren Materialeigenschaften samt kurzer Erklärung und den Parametern,<br />

finden Sie in der newton.wdl unter dem Stichpunkt „Physics material creation and interaction<br />

funstion“.<br />

Das erste eigene Material<br />

Kommen wir zum abschließenden Teil dieses Workshops. Wir werden jetzt unser eigenes Material<br />

erstellen und dies für einen Stapel herumstehender Reifen in unserem Level verwenden. Da wir alle<br />

NGD Dateien in unseren Ordner kopiert haben, können wir diese auch bedenkenlos verändern,<br />

ohne das dies größere Auswirkungen haben könnte.<br />

In der newtonScript2.wdl definieren wir zunächst einen Namen für unser Material, der Ordnung<br />

halber gleich unter den vordefinierten Namen.<br />

// this global variable reprent handles to materials use in the level<br />

var ground_material;<br />

var wood_material;<br />

var ivory_material;<br />

var ice_material;<br />

var water_material;<br />

var tyre_material; // das ist der Name für unser Material<br />

Scrollen Sie wieder runter zu der Funktion NewtonSetupSystem() und erstellen Sie Ihr Material.<br />

// all other material needs to be created<br />

wood_material = NewtonCreateMaterial ();<br />

ivory_material = NewtonCreateMaterial ();<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │25


ice_material = NewtonCreateMaterial ();<br />

water_material = NewtonCreateMaterial ();<br />

tyre_material = NewtonCreateMaterial (); // hiermit erstellt Newton Ihr Material<br />

Da wir bis jetzt kaum verschiedene Physikobjekte in unserem Level haben, bis auf unser Auto<br />

natürlich, reicht es erstmal die Eigenschaften zwischen unserem Material und der Levelgeometrie<br />

festzulegen. Schreiben Sie die folgenden Zeilen in die NewtonSetupSystem() Funktion, ich werde<br />

deren Bedeutung gleich erklären.<br />

NewtonMaterialSetFriction (ground_material, tyre_material, 1.0, 0.9);<br />

NewtonMaterialSetElasticity (ground_material, tyre_material, 0.7);<br />

NewtonMaterialSetDepthRecover (ground_material, tyre_material, 0.2);<br />

NewtonMaterialSetSoundEffect (ice_material, wood_material, hit);<br />

• Friction - Als erstes haben wir die Reibung angegeben (statisch und kinetisch) und da<br />

Reifen ja nicht besonders gut rutschen (so soll es auch sein ;), hab ich hier besonders hohe<br />

Werte genommen.<br />

• Elasticity – Dieser Wert gibt an, wie stark die beiden Körper voneinander abprallen, wobei<br />

er für Reifen sogar noch etwas höher sein könnte. Ein Formel1-Reifen der mitten in der<br />

Fahrt vom Fahrzeug getrennt wird ist quasi nicht zu stoppen – glauben Sie mir!<br />

• DepthRecover - Hier bin ich mir nicht ganz sicher. Scheinbar wird hier angegeben, wie<br />

schnell das gegenseitige Durchdringen zweier Objekte wieder gelöst wird.<br />

• SoundEffect – Definieren Sie eine Sound-Datei, die jedesmal abgespielt wird, wenn beide<br />

Gegenstände aufeinander prallen.<br />

Ihr Material ist bereits voll funktionsfähig, eine Kleinigkeit fehlt aber noch um es in WED auch<br />

zuweisen zu können. Alle die sich etwas auskennen, haben sicherlich bemerkt, dass wir noch eine<br />

Aktion für unser Material brauchen, also legen wir dieses gleich unter den anderen Material-<br />

Aktionen an.<br />

action NewtonIceEntity<br />

{<br />

}<br />

NewtonCreateGravityEntity (ice_material);<br />

// uses mass, linear_drag, angular_drag_x, angular_drag_y, angular_drag_z, health,<br />

shape_factor, collision_groupId, collision_sph_box, start_active, compound_collision,<br />

destructible, spawn_children;<br />

action NewtonTyreEntity<br />

{<br />

}<br />

NewtonCreateGravityEntity (tyre_material);<br />

Das war’s schon. Der Kommentar über unserem Code ist übrigens nicht nur informativ, sondern<br />

auch überaus praktisch, denn die Werte unseres Materials würden ohne diesen Kommentar in WED<br />

statt Mass, Health usw. nur Skill1, Skill2 usw. heißen und das ist sehr unübersichtlich.<br />

Schauen Sie es sich am besten gleich selber an, indem Sie nun endlich den Reifenstapel in unser<br />

Level einbringen. Wechseln Sie zu WED, klicken Object -> Add Model und wählen aus dem Ordner<br />

models\ das Modell rue_360_d.mdl. Fügen Sie noch drei weitere Reifenmodelle ein und platzieren<br />

Sie diese zu einem Stapel, der irgendwo in unserem Raum auf dem Boden steht.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │26


Weisen Sie jedem dieser Reifen die Aktion NewtonTyreEntity zu – das hatten Sie vorher schon bei<br />

der Karosserie und den Autoreifen gemacht – und ändern Sie den Wert Mass auf 20.<br />

Wenn Sie fertig sind, dann speichern und kompilieren Sie Ihr Level und starten es anschließend.<br />

Der Reifenstapel sollte jetzt in Ihrem Raum stehen und auf Kollision mit Ihrem Wagen reagieren.<br />

Falls Ihnen einige Eigenschaften nicht zusagen sollten, dann wissen Sie ja wo diese geändert<br />

werden können.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │27


Glückwunsch, die erste Hürde zum Physik-Flitzer haben Sie gemeistert und allzu schwer war es<br />

auch nicht. Sie sind nun in der Lage, die Eigenschaften Ihres Wagens und einfachen Physikobjekten<br />

Ihren Wünschen anzupassen und haben eine bessere Vorstellung über die Funktionsweise von<br />

NGD.<br />

Schlusswort<br />

Bis zum nächsten Teil dieses Workshops können Sie noch etwas mit den Funktionen und Aktionen<br />

von NGD herum experimentieren. z.Bsp. könnten Sie Ihren Ferrari über hügeliges Terrain steuern<br />

oder völlig unkontrollierbar über Eis schlittern lassen. Und keine Hemmungen, was ich hier<br />

niedergeschrieben habe kam auch nur durch experimentieren und durchstöbern der wdls zustande.<br />

Im nächsten Teil werden Sie, wie schon zu Beginn gesagt, weiter in die Funktionen von NGD<br />

eindringen und mit einigem Skriptaufwand coole Sachen mit Ihrem Wagen anstellen. Es wird also<br />

ganz bestimmt nicht langweilig. Schreiben Sie mir am besten Ihre Wünsche und Anregungen per<br />

Mail und ich werde versuchen diese dann einzubringen, somit haben auch andere etwas von Ihren<br />

Ideen. Je nach Resonanz werde ich dann eventuell noch einen dritten Teil veröffentlichen.<br />

Ich hoffe, es hat Ihnen Spaß gemacht und machen Sie’s gut bis zum nächsten Teil.<br />

Ruben Aster aka Asse.<br />

Asse_<strong>3D</strong>GS@web.de<br />

Vielen Dank noch an Psionic für das ausgezeichnete F360 Modell. Ein Besuch der Seite lohnt sich!<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │28


Inhalt<br />

Ein Nebeltutorial für das <strong>3D</strong> Gamestudio<br />

1.Das Nebelsystem des <strong>3D</strong>GS<br />

2.Eigene Systeme und volumetrischer Nebel<br />

3.Specials: Materials und Dynamik<br />

von Torsten „fogman“ Fock<br />

Ist für Sie das Nebelsystem von <strong>3D</strong> Gamestudio ein Rätsel? Oder haben Sie es verstanden und<br />

wollen noch ganz andere Sachen machen? Dann dürften Sie die folgenden Zeilen interessieren...<br />

Zu allen Kapiteln und Beispielen gibt es Beispiellevels, die das geschriebene Veranschaulichen.<br />

Diese Beispiele können Sie zusammen mit dem Tutorial hier<br />

herunterladen: http://home.arcor.de/braindamaged/Nebeltutorial.rar (Ca. 8.8 MB)<br />

Und nun wünsche ich Ihnen viel Spaß beim experimentieren.<br />

Das Nebelsystem des <strong>3D</strong>GS<br />

Beispiellevel: Beispiel_Teil_1<br />

Wie fast alles im Gamestudio ist das Nebelsystem sehr modular aufgebaut. Es gibt vier<br />

Nebelfarben, die per Skript und im WED verändert werden können. Aus diesen Nebelfarben kann<br />

dann per Skript eine ausgewählt werden.<br />

Schauen Sie sich ein einfaches Skript an, welches von diesen Nebelfarben gebrauch macht:<br />

function fog_fnc()<br />

{<br />

}<br />

d3d_fogcolor1.red = 100; // Nebelfarbe 1, Rotanteil<br />

d3d_fogcolor1.green = 100; // Nebelfarbe 1, Grünanteil<br />

d3d_fogcolor1.blue = 100; // Nebelfarbe 1, Blauanteil<br />

fog_color = 1; // Benutze Nebelfarbe 1<br />

Diese Funktion erzeugt einen grauen Nebel, da alle Farbanteile auf den selben Wert eingestellt<br />

sind.<br />

Weitere Beispiele:<br />

d3d_fogcolor2.red = 255;<br />

d3d_fogcolor2.green = 255;<br />

d3d_fogcolor2.blue = 255;<br />

Erzeugt weißen Nebel mit der Nebelfarbe 2.<br />

d3d_fogcolor4.red = 100;<br />

d3d_fogcolor4.green = 0;<br />

d3d_fogcolor4.blue = 100;<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │29


Erzeugt violetten Nebel mit der Nebelfarbe 4. Mit fog_color können Sie nun zwischen diesen<br />

Nebelfarben umschalten um zu bestimmen, welche angezeigt wird.<br />

fog_color = 4;<br />

Würde dementsprechend den vorher definierten, violetten Nebel darstellen. Es ist nicht unbedingt<br />

nötig, die Nebelfarben per Skript zu setzen.<br />

Im WED können sie diese Farben direkt bestimmen und per Skript jederzeit ändern.<br />

Gehen Sie hierzu in die „Map-Proberties“ im „File-Menü“. Hier können Sie unter „Fog“ die<br />

Nebelfarben direkt setzen. Im Skript wählen Sie dann nur noch per „fog_color“ welche Nebelfarbe<br />

dargestellt werden soll.<br />

Nun müssen Sie noch festlegen, wie dicht der Nebel sein soll. Hierfür gibt es drei Parameter:<br />

„view.fog“, „view.fog_start“ und „view.fog_end“.<br />

„fog_start“ beschreibt die Entfernung in Quants zum View, ab der der Nebel beginnen soll.<br />

„fog_end“ beschreibt die Entfernung zum View, wo der Nebel endet.<br />

Je dichter diese Werte zusammenliegen, desto dichter wird der Nebel sein.<br />

Logisch, oder?<br />

Schreiben Sie also...<br />

function fog_fnc()<br />

{<br />

}<br />

d3d_fogcolor1.red = 100; // Nebelfarbe 1, Rotanteil<br />

d3d_fogcolor1.green = 100; // Nebelfarbe 1, Grünanteil<br />

d3d_fogcolor1.blue = 100; // Nebelfarbe 1, Blauanteil<br />

fog_color = 1; // Benutze Nebelfarbe 1<br />

camera.fog_start = 100; // Der Nebel beginnt 100 Quants entfernt von der Kamera<br />

camera.fog_end = 500; // Der Nebel endet 500 Quants entfernt von der Kamera<br />

Beachten Sie das „camera“ der vordefinierte View ist. Sie können natürlich auch jeden selbst<br />

definierten View benutzen.<br />

Um Texturen direkt vom Nebel zu beeinflussen dient der „albedo“. Ihn können Sie im WED bei<br />

den Texture-Settings einstellen. Werte unter fünf stehen für die Nebelfarbe, fünf selbst für<br />

Dunkelheit. So ist es leicht möglich, Oberflächennebel zu erzeugen.<br />

Um zu bestimmen wie stark sich Nebel auf dynamische Schatten auswirkt, benutzen Sie den<br />

„view.fog“ Parameter.<br />

camera.fog = 0; // Nebel wirkt sich nicht auf dynamische Schatten aus.<br />

camera.fog = 100; // Nebel wirkt sich voll auf dynamische Schatten aus.<br />

Und das war das ganze Geheimnis des Nebelsystems!<br />

Wie, das reicht Ihnen nicht...?<br />

Da muß ich mir ja was einfallen lassen...<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │30


Volumetrischer Nebel und eigene Systeme<br />

Wir kochen unser eigenes Süppchen Bodennebel... Beispiellevel: Beispiel_Teil_2_1<br />

Um volumetrischen Nebel zu erzeugen, welcher die Grundlage für eigene Systeme ist, müssen Sie<br />

tricksen. Das Prinzip werde ich anhand von Bodennebel darlegen.<br />

Dieser wirkt zusammen mit dem standard Nebelsystem äußerst atmosphärisch:<br />

Hierfür benötigen Sie zuerst mal den normalen Nebel. Die Funktion kennen sie ja schon.<br />

function fog_fnc()<br />

{<br />

}<br />

d3d_fogcolor1.red = 100; // Nebelfarbe 1, Rotanteil<br />

d3d_fogcolor1.green = 100; // Nebelfarbe 1, Grünanteil<br />

d3d_fogcolor1.blue = 100; // Nebelfarbe 1, Blauanteil<br />

fog_color = 1; // Benutze Nebelfarbe 1<br />

camera.fog_start = 100; // Der Nebel beginnt 100 Quants entfernt von der Kamera<br />

camera.fog_end = 500; // Der Nebel endet 500 Quants entfernt von der Kamera<br />

Starten Sie nun MED. Erstellen Sie einen Würfel und löschen Sie alle Vertices bis auf die obersten<br />

vier, und geben Sie der verbliebenen Fläche eine hellgraue Skin:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │31


Speichern Sie das Modell in Ihrem Projektordner und laden Sie es zwölfmal in Ihr Level. Skalieren<br />

Sie die Modelle so, das sie in den schon erzeugten Nebel hineinragen werden, und ordnen Sie sie in<br />

geringen Abständen übereinander an:<br />

Eine kleine Action benötigen Ihre Modelle auch noch, um sie transparent zu machen und an die<br />

Kamera anzuhängen.<br />

Wie wäre es damit:<br />

action fog_disc<br />

{<br />

my.transparent = on;<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │32


}<br />

my.alpha = 10;<br />

while(1)<br />

{<br />

}<br />

my.x = camera.x;<br />

my.y = camera.y;<br />

wait(1);<br />

Die Modelle werden also transparent sein, mit einem geringen Alphawert. Sonst wäre der<br />

Bodennebel zu „dicht“. Mit der while-Schleife erzwingen Sie, das die x und y Positionen der<br />

„Nebelplatten“ immer denen der Kamera entsprechen.<br />

Da sich Bodennebel am Boden am wohlsten fühlt, lassen wir die z Position unberührt. Weisen Sie<br />

den Modellen die Action zu, und Sie haben Ihren ersten eigenen, volumetrischen Nebel erzeugt!<br />

Eigene Systeme... Beispiellevel: Beispiel_Teil_2_2<br />

Nun können Sie sich gewiß schon denken, wie Sie ein komplett eigenes System realisieren<br />

könnten. Ich möchte auch nicht weiter auf die Gründe eingehen, Sie werden welche haben. Viele<br />

Wege führen auch hier nach Rom, ich möchte einen davon vorstellen.<br />

Zuerst benötigen Sie wieder den MED oder einen anderen Modeller. Erschaffen Sie dort bitte einen<br />

einfachen Zylinder und löschen alle Vertices bis auf die untersten. Geben Sie auch dieser Fläche die<br />

graue Skin:<br />

Nun ziehen Sie den mittleren Vertex nach oben – etwa so:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │33


Speichern Sie das Modell und öffnen Sie Ihr Level in WED. Fügen Sie das Modell wieder zwölfmal<br />

ein – je öfter umso feiner wird Ihr Nebel aufgelöst sein. Übertreiben Sie es aber nicht!<br />

Hier sehen Sie die eingefügten Modelle. Ich habe jedes folgende etwas größer skaliert:<br />

Kommen wir zur dazugehörigen Action:<br />

action fog_disc_2<br />

{<br />

my.transparent = on;<br />

my.alpha = 10;<br />

while(1)<br />

{<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │34


}<br />

}<br />

my.x = camera.x;<br />

my.y = camera.y;<br />

wait(1);<br />

Nein, Sie haben sich nicht verlesen. Es ist genau die gleiche Action die ich für den Bodennebel<br />

verwendet habe, bis auf ihren Namen. Wenn gewünscht, kann die z – Position natürlich auch noch<br />

an die Kamera gehängt werden.<br />

Es ist nur ein Weg, Modelle zu benutzen. Ebenso geht es mit Map Entities oder Sprites ja selbst<br />

Terrain könnten Sie mißbrauchen. Ich habe mich für Modelle entschieden, da diese schnell<br />

gerendert werden und man viele weitergehende Sachen mit ihnen anstellen kann. Was halten Sie<br />

zum Beispiel von ein paar Materialien und waberndem Nebel?<br />

Sehen Sie – ich auch...<br />

Specials: Material und Dynamik<br />

Wunderliche Waschküchen... Beispiellevel: Beispiel_Teil_3<br />

Anhand eines „Nebelsees“ werde ich Ihnen eine Möglichkeit zeigen, dynamischen Nebel zu<br />

erzeugen.<br />

Zu diesem Zweck benötigen Sie ein einfaches Terrain mit einer Vertiefung. Für eben diese<br />

Vertiefung müssen Sie ein Modell erstellen. Beginnen Sie also wieder mit dem MED:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │35


Ich habe einfach das Terrain in ein Modell gewandelt (im Edit-Menü), und alle Vertices gelöscht bis<br />

auf die Vertiefung. Diese habe ich dann mit dem Scale -Tool zu einer planen Fläche gemacht und<br />

ihr die graue Skin gegeben. In WED müssen Sie dieses Modell nun über der Vertiefung im Terrain<br />

platzieren. Laden Sie das Modell dreimal in den WED und verschieben Sie sie etwas<br />

gegeneinander:<br />

Um eine schönere Gesamtatmosphäre zu erzeugen, laden Sie bitte auch noch das Bodennebel –<br />

Modell zwölfmal in den Leveleditor. Ordnen Sie die Flächen so an, wie in Kapitel 2 beschrieben:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │36


Lassen Sie uns dem Nebel Leben einhauchen. Dazu brauchen wir etwas C-Script. Fügen Sie die<br />

folgenden, schon bekannten Funktionen ein um Bodennebel und normalen Nebel zu erhalten:<br />

function fog_fnc()<br />

{<br />

}<br />

d3d_fogcolor1.red = 100; // Nebelfarbe 1, Rotanteil<br />

d3d_fogcolor1.green = 100; // Nebelfarbe 1, Grünanteil<br />

d3d_fogcolor1.blue = 100; // Nebelfarbe 1, Blauanteil<br />

fog_color = 1; // Benutze Nebelfarbe 1<br />

camera.fog_start = 100; // Der Nebel beginnt 100 Quants entfernt von der Kamera<br />

camera.fog_end = 500; // Der Nebel endet 500 Quants entfernt von der Kamera<br />

action fog_disc<br />

{<br />

}<br />

my.transparent = on;<br />

my.alpha = 10;<br />

while(1)<br />

{<br />

}<br />

my.x = camera.x;<br />

my.y = camera.y;<br />

wait(1);<br />

Weisen Sie bitte den zwölf Bodennebel Modellen die Action „fog_disc“ zu. Und vergessen Sie nicht,<br />

die Funktion „fog_function( )“ zu starten!<br />

Nun wird es ein wenig komplizierter. Sie haben sich bestimmt schon Gedanken gemacht, wie man<br />

die drei Flächen für den Nebelsee wabern läßt. Da gäbe es die Möglichkeit die Flächen im MED zu<br />

animieren. Aus verschiedenen Gründen habe ich mich für eine andere Art der Animation<br />

entschieden.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │37


Animierte Modelle würden auf Dauer langweilig aussehen, brauchen mehr Speicher und sind<br />

langsamer in der Berechnung. Lassen Sie uns also eine Action schreiben, die direkt auf die Vertices<br />

der Modelle wirkt, auch „Meshdeforming“ genannt.<br />

Vor dieser Funktion graut es mir am meisten, da sie sich auf Sinusberechnung stützt.<br />

Frisch ans Werk, ich werde Ihnen jede Zeile erklären:<br />

var counter;<br />

var index;<br />

var vertices = 241;<br />

var vertex_array[241];<br />

Diese vier Zeilen definieren drei Variablen und einen Array. Ein Modell für den Nebelsee hat 241<br />

Vertices. Daher dieser Eintrag.<br />

action fog_dynamic<br />

{<br />

my.transparent = on;<br />

my.passable = on;<br />

my.alpha = 15;<br />

while (counter < vertices) // Solange Counterwert kleiner Verticeswert<br />

{<br />

den Array<br />

Temp<br />

vertex_array[counter] = random(360); // Setze Zufallswerte von 0-360 in<br />

counter += 1; // Zähle den Arrayindex um eins hoch<br />

while (1)<br />

{<br />

den Z - Eintrag<br />

Vektor<br />

}<br />

}<br />

while (index < vertices) // Solange Indexwert kleiner Verticeswert<br />

{<br />

}<br />

vec_for_mesh(temp, my, index); // Aktuelle Vertexposition in<br />

temp.z = sin(counter + vertex_array[index]) * 1; // Ändere<br />

vec_to_mesh(temp, my, index); // Bewege den Vertice mit dem<br />

index += 1; // Zähle eins auf den Index<br />

counter += 0.2 * time; // Zähle den Counter hoch<br />

index = 0; // Setze index auf null<br />

wait(1);<br />

Was für ein Monster! Keine Angst, Sie werden sehen, es ist durchaus einfach zu verstehen.<br />

Die ersten drei Zeilen sollten selbsterklärend sein. Das Modell wird transparent und passabel<br />

gemacht, der Alphawert der Transparenz beträgt 15.<br />

Als nächstes folgt eine Schleife, die solange durchlaufen wird, bis die Variable „counter“ einen Wert<br />

von 241 hat. Jener Wert der in der Variable „vertices“ steht. In dieser Schleife werden nun alle 241<br />

Einträge des Arrays mit Zufallszahlen von 0 – 360 gefüllt. Auf den „Counter“ wird jeweils eins<br />

hinzuaddiert, so das die Schleife nach dem 241. Lauf endet. Aufgrund der Abbruchbedingung<br />

können wir in der Schleife auf ein „wait“ verzichten. Es kann keine Endlosschleife entstehen.<br />

In der nächsten Zeile beginnt eine solche „Endlosschleife“. Und in ihr noch eine Schleife. Man nennt<br />

so etwas „verschachtelt“. Es wird also permanent („endlos“) geprüft, ob sich die Bedingung erfüllt<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │38


und die zweite Schleife aktiv wird. Da der die Variable „index“ null ist und in der Schleife wieder<br />

um eins hochgezählt wird, wird sie 241 mal durchlaufen.<br />

Der Befehl „vec_for_mesh“ liest die Vertexposition des Vertices der durch den „index“ ausgewählt<br />

wurde und kopiert sie in den vordefinierten Vektor „temp“. Die Z-Komponente des Vektors wir nun<br />

in einer Sinusfunktion verändert, abhängig vom Wert des „counters“ und dem aktuellen<br />

„Winkeleintrag“ (0-360) in dem Array.<br />

Per „vec_to_mesh“ wird die Vektorposition dem per index ausgewähltem Vertice wieder<br />

„aufgezwungen“ - er bewegt sich auf der Z-Achse. Natürlich muß der „index“ dann wieder um eins<br />

hochgezählt werden, um den nächsten Vertex zu bedienen. Wenn alle Vertices ein Stückchen<br />

bewegt wurden, wird die Schleife verlassen. Der Counterwert wird erhöht, um die Vertices beim<br />

nächsten Durchlauf weiterzubewegen. Die Variable „index“ wird auf null gesetzt – das Spiel beginnt<br />

von vorne.<br />

Spielen Sie ein wenig mit der Action – sie eignet sich auch als Grundstock für Gardinen, Wasser<br />

und was sonst noch so „wabert oder wellt“<br />

Weisen Sie diese Action den „Nebelseemodellen“ zu. Nun haben Sie ihren ersten dynamischen<br />

Nebel erzeugt. Lassen Sie uns noch rasch ein Material für den Nebel definieren. Sie werden<br />

überrascht von den Effekten sein, die wie Wasser oder Toxien wirken können.<br />

Schauen wir uns seine Definition an:<br />

material fog_mat<br />

{<br />

}<br />

ambient_red = 10;<br />

ambient_green =10;<br />

ambient_blue = 10;<br />

diffuse_red = 0;<br />

diffuse_green = 100;<br />

diffuse_blue = 0;<br />

specular_red = 0;<br />

specular_green = 255;<br />

specular_blue = 0;<br />

emissive_red = 0;<br />

emissive_green = 100;<br />

emissive_blue = 0;<br />

power = 5;<br />

Die Grundhelligkeit (Ambient) beträgt 10.<br />

Diffuse beschreibt, wieviel Licht und welche Farbe das Material empfangen kann.<br />

Specular setzt einen Glanzpunkt<br />

Emissive bestimmt mit welchem Wert sich die Entity illuminiert.<br />

Power steht für die Größe des Glanzpunktes.<br />

Schreiben Sie in die Action „fog_dynamic folgendes, gleich unter „my.passable = on;“ :<br />

my.material = fog_mat;<br />

Nun haben Sie dem Nebelsee ein Material zugewiesen. Was noch fehlt ist ein dynamisches Licht,<br />

um die Auswirkungen des Effekts richtig zu sehen.<br />

Sie können ein einfaches Modell nehmen (z. B. einen Würfel) und diesem die folgende Action<br />

geben:<br />

action light_dyn<br />

{<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │39


}<br />

my.invisible = on;<br />

my.lightrange = 300;<br />

my.red = 255;<br />

my.green = 255;<br />

my.blue = 255;<br />

Platzieren Sie Ihre „Sonne“ dicht über dem Nebelsee, builden Sie und starten Sie Ihren Rundgang<br />

durch ein radioaktives Medium.<br />

Nun sind wir am Ende des Tutorials angelangt. Ich hoffe ich konnte Ihnen einige Inspiration über<br />

den kreativen Umgang mit Dunst verschaffen.<br />

Versuchen Sie, das Material zur Laufzeit zu beeinflussen, indem Sie seine Parameter in einer<br />

Funktion verändern, ändern Sie die Skin, oder, oder, oder...<br />

Lassen Sie es mich wissen, wenn Sie einen neuen Effekt ausgetüftelt haben und verlaufen Sie sich<br />

nicht. Sonst muß ich auch noch ein Nebelhorntutorial schreiben.<br />

In diesem Sinne – Rauchen Sie ab!<br />

Torsten „fogman“ Fock<br />

fogman@gmx.com<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │40


Modelldesign - Teil 1: Mesh eines Tischs mit Blender<br />

Einleitung<br />

von Josef/Jupp<br />

Hallo ich bin Josef Brandl und dürfte Ihnen als Josef oder Jupp aus dem <strong>3D</strong>GS-User Forum bekannt<br />

sein. In dieser Reihe werde ich zeigen, wie man professionelle Modelle mit Blender erstellt. Warum<br />

mit Blender und nicht MED? In MED wird sich einiges mit dem nächsten Update ändern, außerdem<br />

kommen Fortgeschrittene schnell an die Grenzen MEDs. In Blender gibt es weitaus mehr Features.<br />

Es ist fast unmöglich alle zu kennen, allein das Handbuch erfasst 686 Seiten. Ein weiterer guter<br />

Grund ist, dass Blender opensource ist, das heißt nicht nur, dass es laufend Updates gibt sondern<br />

auch, dass sich jeder das Programm kostenlos aus dem Internet runterladen kann. Ich hoffe, dass<br />

ich dem einen oder anderen mit diesem Tutorial einen Gefallen tue.<br />

Viel Spaß beim Lesen<br />

Josef<br />

Der Start: Was wird benötigt?<br />

Wir brauchen für diesen Part nur den Open Source Modeller Blender. Sie bekommen die aktuelle<br />

Version bei www.blender3d.org .<br />

Die Tischplatte<br />

Zu allererst öffnen wir das Programm, wir sehen den Standardwürfel. Die rosa Linie um ihn herum<br />

bedeutet, dass er selektiert wurde. Ich habe ihnen eine Auflistung über die Funktionen der Maus<br />

zusammengestellt. Prägen sie sich diese gut ein, dann können wir loslegen.<br />

Info: Die Funktionen der Maus<br />

Linke Maustaste – Ist in Blender fast nur für das Drücken der Buttons zuständig. Außerdem lassen<br />

sich damit Arbeitsschritte abschließen (wie z.B. eine Verschiebung oder Skalierung) und<br />

Mausgesten zeichnen. Ich habe drei Gesten herausgefunden: 1) Malt man eine gerade Linie, so<br />

aktiviert man das Verschiebewerkzeug 2) Malt man einen Kreis, so aktiviert man das<br />

Rotationswerkzeug 3) Malt man ein "V", so aktiviert man das Skalierungswerkzeug. Nach längerer<br />

Arbeit mir Blender kann ich allerdings sagen, dass es viel einfacher ist, wenn man die Hotkeys auf<br />

der Tastatur her nimmt.<br />

Mittlere Maustaste – Diese Taste wurde bei neuen Mäusen durch ein drückbares Mausrad ersetzt.<br />

Mit dieser Taste lässt sich u. a. die Ansicht des <strong>3D</strong> Ports, auf dem Sie sich gerade mit dem Cursor<br />

befinden, rotieren. Sie werden dabei feststellen, dass es entscheidend ist, wo sie gerade Ihren<br />

Cursor auf dem <strong>3D</strong> Port haben. Denn ist die Position weiter außen, so rollt die Kamera, ist die<br />

Position mehr nahe der Mitte, so schaut man sich um. Probieren sie das gleich mal aus. Ich zeige<br />

im Anschluss, wie sie die Kamera wieder zu Ursprungsposition zurückbringen. Wenn Sie zusätzlich<br />

shift drücken, dann können Sie die Ansicht verschieben .Drücken Sie zusätzlich strg, dann zoomen<br />

Sie, allerdings wenn sie ein Mausrad haben, dann nehmen Sie doch das dafür her.<br />

Rechte Maustaste – Es lassen sich damit einzelne Vertices/Edges/Faces/Objectes selektieren,<br />

drücken Sie shift um eine Auswahl damit zu erweitern. Auch können Sie den aktuellen Schritt<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │41


damit abbrechen, z.B. eine Verschiebung.<br />

Genug der Theorie. Lasst uns weiterarbeiten. Der schon vorhandene Würfel ist für einen Tisch<br />

genau das Richtige, darum können wir direkt anfangen ihn zu editieren. Oder anders: Wir wechseln<br />

in den Editiermodus. Das machen wir entweder mit der Tabulator Taste oder wählen in dem Header<br />

des Views den "Editmode" aus.<br />

Drücken Sie im Anschluss die A-Taste, um alles zu de-selektieren.<br />

Info: Die A-Taste<br />

• Diese Taste macht falls es Selektiertes gibt alles un-selektiert, falls nicht wird einfach alles<br />

selektiert.<br />

• Wechseln Sie in die Oben-Ansicht, per Druck auf die 7 des Nummerblocks.<br />

Info: Der Nummernblock<br />

• 0 – Die Ansicht der Kamera<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │42


• 1 – Die x,z Ansicht (von vorne)<br />

• 1 + strg – Die -x,z Ansicht (von hinten)<br />

• 2 – Die Kamera nach unten drehen<br />

• 3 – Die y,z Ansicht (von rechts)<br />

• 3 + strg – Die -y,z Ansicht (von links)<br />

• 4 – Die Kamera nach links drehen<br />

• 5 – Umschalter zwischen perspektivischer und orthographischer Ansicht. Bei der<br />

perspektivischen Ansicht werden anders wie bei der orthographischen Ansicht die Objekte je<br />

weiter sie weg sind kleiner.<br />

• 6 – Die Kamera nach rechts drehen<br />

• 7 – Die x,y Ansicht (von oben)<br />

• 7 + strg – Die -x,y Ansicht (von unten)<br />

• 8 - Die Kamera nach oben drehen<br />

Anmerkung:<br />

Dies wirkt sich auf die <strong>3D</strong> View aus über der sich die Maus gerade befindet.<br />

Sie sehen nun alles von Oben. Ein Druck B-Taste aktiviert das Werkzeug für ein Auswahlrechteck,<br />

das funktioniert so etwa wie in MED oder in Malprogrammen, wie Gimp und Paint. Wir selektieren<br />

damit die Vertices einer Seite unseres Tisches. Die selektierten Vertices werden nun gelb.<br />

Info: Die Bedeutung der Farben im Edit Mode<br />

selektiert unselektiert<br />

Vertices hellgelb violett<br />

Edges dunkelgelb schwarz<br />

Faces rosa blau<br />

Wenn Sie die Kamera ein wenig bewegen, dann sehen Sie, dass wir nicht erreicht haben, was wir<br />

eigentlich wollten. Wir haben nicht alle Vertices auf der Seite selektieren können. Woran das wohl<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │43


liegt?<br />

Die Antwort ist eigentlich ganz einfach: Die Auswahl ist standardmäßig auf Sichtbares limitiert.<br />

Schalten Sie den hier rot eingezeichneten Button aus und wiederholen sie dann die Prozedur mit<br />

der Box (B-Taste).<br />

Wir sehen, dass jetzt alle 4 Vertices selektiert sind. Nun stellen Sie sicher, dass Sie in der Top<br />

Ansicht sind (7). Drücken Sie die E-Taste für eine Extrusion. Wir wählen Region. Bewegen Sie die<br />

Maus. Sie sehen jetzt die neuen Faces die entstanden sind. (Folgendes ist für später wichtig) Die<br />

eigentliche Extrusion ist abgeschlossen! Sie befinden sich nur noch im Verschiebe-Modus, d.h.,<br />

wenn Sie die rechte Maustaste drücken um die Aktion abzubrechen, sind die neu entstandenen<br />

Faces immer noch vorhanden. Sie müssen zusätzlich noch die Kombination aus strg+z-Taste<br />

drücken um auch die Extrusion rückgängig zu machen. Mit einem Druck von strg bewegen wir<br />

unsere Selektion am Raster. Wir verschieben das Ganze nur um ein Kästchen. Per Druck der linken<br />

Maustaste bestätigen Sie. Machen Sie das auch mit der anderen Seite unseres zukünftigen Tischs.<br />

Das Resultat:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │44


Jetzt kommt wieder das Auswahlviereck dran. Selektieren Sie die Vertices an der linken und<br />

rechten Kante. Nicht vergessen: Dieses Tool fügt die neuen Vertices immer zur bestehenden<br />

Auswahl hinzu, d.h. sie brauchen keine zusätzliche Taste drücken, um die Auswahl zu vergrößern.<br />

Wir wollen nun diese Ecken reinskalieren, sodass der Tisch nachher abgerundete Kanten hat.<br />

Drücken Sie es um die selektierte Auswahl zu skalieren. Drücken Sie danach y um die Vertices<br />

entlang der y-Achse zu skalieren. In welche Richtung welche Achse geht sehen sie unten links im<br />

<strong>3D</strong> Port. Halten Sie dann noch strg gedrückt um am Raster zu skalieren. Per Druck der linken<br />

Maustaste bestätigen sie die Aktion.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │45


Wechseln wir nun in die Frontansicht (1) Drücken Sie die A-Taste um alle Vertices zu selektieren.<br />

Nun drücken sie „S“ um wieder zu skalieren. Wir wollen unseren Tisch nun auf eine normale dicke<br />

bringen. Wählen sie mit einem druck der z Taste die z Achse aus und skalieren die platte nun<br />

ungefähr so dick wie auf folgendem Bild:<br />

In der Top Ansicht machen wir jetzt den Tisch noch etwas länglicher, indem wir jeweils die Vertices<br />

oben und unten ein wenig nach innen verschieben. Sie können dazu dieses Verschiebewerkzeug<br />

mit den Pfeilen hernehmen. Wenn sie es nicht haben, dann stellen sie sicher, dass diese Buttons<br />

des View-Headers, siehe Bild, gedrückt sind: Sie wollen nicht immer dieses Werkzeug hernehmen?<br />

Sie können auch G für Grab drücken. Letztlich ist es egal wie sie ihre Auswahl verschieben.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │46


Das Untergestell<br />

Jeder Tisch hat direkt unter der Platte ein paar Streben. Da wir die grundlegenden Funktionen jetzt<br />

besprochen haben werde ich das jetzt kürzer fassen.<br />

Vergewissern sie sich, dass sie in der Top-Ansicht sind und rufen durch Drücken der Leertaste ein<br />

Menü auf. Wählen sie Add >> Plane. Nun haben wir ein flache Platte erstellt. Drücken sie E >><br />

Region für eine Extrusion. Drücken sie Esc und dann S zum reinskalieren. Ihr Ergebnis dürfte in<br />

etwa so aussehen:<br />

Also was haben wir gemacht. Wir haben aus einer flachen Platte durch Extrusion Faces rundherum<br />

erstellt, da die sich aber in der Höhe nicht unterscheiden sollen brachen wir die Verschiebung ab.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │47


Richtig: Das würde auch mit der rechten Maustaste gehen.<br />

Nun wechseln wir in den Face Select Mode. Sie dachten sich höchstwahrscheinlich schon, dass<br />

Blender, ähnlich zu med oder wings auch verschiedene Selektionsmodi hat. Den Selektionsmodus<br />

können sie bequem in View-Header auswählen:<br />

Lasst uns die großen Faces des Planes auswählen, denn die müssen weg. Klicken sie dazu mit der<br />

rechten Maustaste auf den mittleren Punkt, drücken sie entf >>> faces<br />

Den zweiten mittleren Punkt löschen sie auch noch, so bleibt ein Ring übrig. Bei diesem Ring<br />

verwenden wir jetzt eine Extrusion um ihn wie ein Untergestell aussehen zu lassen.<br />

Jetzt müssen wir diesen Ring nur noch verschieben und vielleicht etwas rumskalieren, damit er so<br />

wie in diesem Bild unter der Tischplatte sitzt.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │48


Die Tischbeine<br />

Ein jeder Tisch hat Beine, aber da gibt es auch unterschiedliche, auf jeden Fall verstehe ich zum<br />

Beispiel unter einem Tischbein keinen viereckigen Klotz.<br />

Wir fangen diesmal wieder mit einem Würfel an. Sie wissen jetzt ja wie man neue Formen<br />

hinzufügt und diese bearbeitet, also erstellen sie so einen Cube und Modellieren daraus ein<br />

Tischbein.<br />

Sie können sich entweder an meiner Form orientieren oder eine ganz neue Kreation schaffen.<br />

Bewegen sie den Cursor über das Tischbein und drücken sie die L-Taste. Blender selektiert es so<br />

automatisch. Was macht Blender da genau? Antwort: Er sucht sich den zum Mauscursor<br />

nächstgelegenen Vertex und selektiert ihn und all seine mit ihm verbundenen Vertices.<br />

Wir duplizieren nun einfach das Bein per shift+d. Drücken sie x um es nur entlang der x-Achse zu<br />

verschieben. Bestätigen sie mit Enter/linke Maustaste.<br />

Jetzt müssen wir das neue Bein noch spiegeln, das ist durch eine Skalierung möglich. Drücken sie<br />

S um das Bein zu skalieren und wieder x für die x-Achse, nun geben sie -1 mit dem Nummernblock<br />

ein. Drücken sie Enter zum bestätigen. Verschieben sie es nun noch zur Richtigen Stelle.<br />

Die gleiche Prozedur jetzt mit den beiden nun erstellten Beinen in der Seitenansicht.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │49


Schluss<br />

Und fertig ist der Tisch… nein nicht ganz, aber das können sie auf diesem Bild jetzt nicht sehen.<br />

Die Normalen der Faces der Beine sind durch das Spiegeln auf der falschen Seite. Sichtbar können<br />

sie das machen, indem sie unten bei den Buttons im mesh-fenster den „double sided“-Button<br />

abwählen. Jetzt sehen sie es auch, dass manche faces viel dunkler sind als andere. Im<br />

Objektmodus sehen sie die dunklen gar nicht. Drücken sie strg+n um dies zu beheben. Blender<br />

kalkuliert nun die Normalen neu.<br />

Fertig ist der Tischmesh. In der nächsten <strong>Ausgabe</strong> werde ich erklären, wie man dieses Mesh<br />

"beskinnt". In einem weiteren Teil wird noch dran kommen, wie man das Modell nach MED<br />

exportiert.<br />

Bei Fragen und Anregungen kontaktiert mich im Gamestudio Forum. Meinen Nickname kennt ihr ja.<br />

Ich wünsche noch viel Spaß mit Blender. Bis zur nächsten <strong>Ausgabe</strong>!<br />

"happy blending!"<br />

Josef/Jupp<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │50


Laser - und Photonentorpedoeffekte<br />

von tuschcarsten<br />

Hallo und herzlich Willkommen zum Waffeneffekt-Artikel des <strong>3D</strong>GS <strong>Magazin</strong>s.<br />

Ich wurde schon oft gefragt, wie man Laser-oder Torpedoeffekte macht. Hier die Lösung:<br />

Laserstrahl<br />

Der Strahl soll so aussehen, wenn er fertig ist:<br />

Als erstes machen wir das Modell für den Laserstrahl.<br />

Dazu öffnen wir MED, fügen einen Würfel ein und löschen alle Seiten bis auf eine:<br />

Dann gehen wir in den Polygon-Modus (links oben) und markieren alles. Dann auf [Edit]->[copy<br />

selected] klicken, dann auf paste. Wir gehen wieder in den Vertex-Modus und markieren wieder<br />

alles. Dann auf den [Merge] Button (oben rechts) klicken. Das bewirkt, dass die Faces jetzt<br />

beidseitig ausgerichtet sind.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │51


Jetzt geben wir dem Modell einen Skin und klicken dazu auf [view]->[Skin].<br />

dann ändern wir die Größe des Skins: [Edit]->[resize skin] und geben die Werte 128x32 ein.<br />

Jetzt stellen wir sicher, dass im normalen Editor (nicht im Skin-Editor) alle Faces markiert sind und<br />

klicken im Skin Editor auf [Edit]->[create md2 mapping] und wählen die Option [TOP] aus.<br />

Das gleiche machen wir noch einmal mit der Option [Bottom].<br />

Dann Ziehen wir die Vertices so zurecht, dass die Faces die Skin-map voll ausfüllen.<br />

Dann exportieren wir das ganze als bmp.<br />

Um die soeben gespeicherte Datei zu bearbeiten, öffnen wir sie in Paint. Als erstes muss alles<br />

schwarz gemalt werden (wenn es das nicht schon ist). Dann speichern wir die Datei mit [Speichern<br />

unter..] als 24-Bit Bitmap ab (ACHTUNG: nicht mit 256 Farben).<br />

Dann malen wir einen dicken farbigen strich von links nach rechts durch die Bitmap. Danach noch<br />

einen kleineren weißen Strich in den ersten Strich hinein:<br />

Jetzt das ganze noch mit einem Bildbearbeitungsprogramm wie Photoshop, Photo Express, Gimp<br />

oder Photo Impression schön unscharf machen und fertig ist die Skin-map.<br />

Jetzt müssen wir sie nur noch im Skin Editor von MED importieren:<br />

[View]->[Skins]<br />

[File]->[import skin image].<br />

Jetzt wird der Skin-Editor geschlossen und nochmal gemodelt:<br />

Wir markieren alle vertices und kopieren sie wie oben schon beschrieben. Dann drehen wir sie um<br />

90°, bis sie so aussehen:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │52


Und dann immer so weiter, bis es so aussieht:<br />

{<br />

}<br />

my.bright = on; //scheint hell<br />

my.ambient = 100; //100% Helligkeit<br />

my.unlit = on; //reagiert nicht auf externes Licht und Schatten<br />

my.overlay = on; //kein Schwarz<br />

my.flare = on; //transparent<br />

my.green = 50; //lichtwerte....<br />

my.blue = 200;<br />

my.lightrange = 50;<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │53


Photonentorpedos<br />

Die Photonentorpedos funktionieren in etwa genauso:<br />

Wir öffnen wieder MED und fügen einen Würfel ein.<br />

Wir löschen alle Flächen, bis auf eine, kopieren diese und kehren die Normals um(wie beim<br />

Laserstrahl). Dann markieren wir alle Faces (im Face_mode) und öffnen den Skin Editor.<br />

Dann ändern wir die Größe des Skins: [Edit]->[resize skin] und geben z.B. die Werte 84x81 ein.<br />

Jetzt klicken wir auf [Edit]->[create md2 mapping] und wählen die Option [TOP] aus. Das gleiche<br />

machen wir noch einmal mit der Option [Bottom].<br />

Dann Ziehen wir die Vertices so zurecht, dass die Faces die Skin-map voll ausfüllen.<br />

Dann exportieren wir das ganze als bmp.<br />

Diese Bmp öffnen wir dann mit Paint und malen ein paar rote und orange Striche von der Mitte aus<br />

nach außen. Dann öffnen wir ein anderes Bildbearbeitungsprogramm wie Photoshop o.a. und<br />

verwischen das Ganze. Die Bmp sollte nun etwa so aussehen:<br />

Jetzt müssen wir sie nur noch im Skin Editor von MED importieren:<br />

[View]->[Skins]<br />

[File]->[import skin image].<br />

Jetzt wird der Skin-Editor geschlossen und nochmal gemodelt:<br />

Wir markieren alle vertices und kopieren sie wie oben schon beschrieben. Dann drehen wir sie um<br />

90°, das selbe wiederholen wir solange, bis es so aussieht:<br />

Dann noch das Modell speichern und diese Aktion zuweisen:<br />

action torpedo<br />

{<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │54


}<br />

my.bright = on; //scheint hell<br />

my.ambient = 100; //100% Helligkeit<br />

my.unlit = on; //reagiert nicht auf externes Licht und Schatten<br />

my.overlay = on; //kein Schwarz<br />

my.flare = on; //transparent<br />

my.green = 50; //lichtwerte....<br />

my.red = 200;<br />

my.lightrange = 50;<br />

mfg<br />

euer tuschcarsten<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │55


Bit-Operatoren<br />

von mk.1<br />

Neben den bekannten Rechenoperatoren wie das bekannte Addieren, Subtrahieren, Multiplizieren<br />

und Dividieren gibt es eine Reihe weiterer Operatoren: Die Bit-Operatoren.<br />

Durch ist es erst möglich, Rechenmaschinen wie die heutigen Home-PCs zu konstruieren. Obwohl<br />

sehr primitiv sind sie sehr häufig von großem Nutzen. Es gibt eine Vielzahl von Bit-Operatoren. Die<br />

bekanntesten sind "und", "oder" und "nicht".<br />

Wie funktionieren Bit-Operatoren?<br />

Um mit Bit-Operatoren zu arbeiten, müssen Sie zuallererst wissen, was ein Bit ist.<br />

Das Wort "Bit" ist eine Abkürzung für "binary digit" (eng.: Binärziffer). Während eine Dezimalziffer<br />

(in unserem Dezimalsystem) zehn Zustände haben kann die Zahlen null bis neun), kann ein Bit<br />

nur den Zustand 1 oder 0 annehmen. Je nach Verwendung spricht man auch von true (wahr) und<br />

false (falsch) oder Signal und kein Signal.<br />

Bit-Operatoren funktionieren wie andere Operatoren auch. Zwei Inputs ergeben ein Output. Hier<br />

ein Beispiel für die Addition:<br />

Ein Bit-Operator funktioniert genauso – zwei Inputs, ein Output.<br />

Bit-Operator "und"<br />

In C-Script (sowie den allen anderen neueren Programmiersprachen) wird das Kaufmanns-Und "&"<br />

für den AND-Operator verwendet. Der Output ist immer dann true (1), wenn beide Inputs true (1)<br />

sind:<br />

Die folgende Tabelle zeigt alle möglichen Kombinationen:<br />

0<br />

1<br />

0<br />

1<br />

&<br />

0<br />

0<br />

1<br />

1<br />

=<br />

0<br />

0<br />

0<br />

1<br />

Bit-Operator "oder"<br />

Dieser Operator hat immer dann den Output true, wenn mindestens einer der Inputs true ist:<br />

0<br />

1<br />

0<br />

1<br />

&<br />

0<br />

0<br />

1<br />

1<br />

=<br />

0<br />

1<br />

1<br />

1<br />

Dieser Operator wird durch einen geraden Strich "|" dargestellt.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │56


Das Binärsystem<br />

Das heutige weltweite System ist das Dezimalsystem, welches die 10 Ziffern 0-9 kennt. Neben<br />

unserem System gibt es unendlich viele andere, wie das Hexadezimale System (16 Ziffern), das<br />

Oktalsystem (8 Ziffern), das Binärsystem (2 Ziffern). Die Babyloner verwendeten sogar ein System<br />

mit 60 verschiedenen Ziffern.<br />

Da ein Computer nur zwei Zustände kennt (Signal/kein Signal), ist das Binärsystem das sinnvollste<br />

System zum Rechnen. Wenn Sie an die erste Grundschule zurückdenken, erinnern Sie sich<br />

vielleicht an die "Einer, Zehner, Hunderter". Sie waren Ausdrücke für eine weitere "Stelle" im<br />

System. Die Zahlen null bis neun benötigen, nur eine Stelle, die Zahlen 10 bis 99 zwei Stellen und<br />

so weiter. Das bedeutet, dass Sie, sobald alle Ziffern verwendet wurden, eine neue Stelle<br />

brauchen. Dieses Problem tritt auch im Binärsystem auf, da es nur zwei Ziffern gibt, die Null und<br />

die Eins. Wenn Sie die Zwei darstellen wollen, benötigen Sie bereits zwei Ziffern.<br />

Dezimal Binär<br />

0 0<br />

1 1<br />

2 10<br />

3 11<br />

4 100<br />

5 1<strong>01</strong><br />

6 110<br />

Um eine Zahl aus dem Binärsystem in das Dezimalsystem umzurechnen, bedarf es einiger<br />

Denkarbeit. Im Binärsytem wird immer dann eine neue Stelle verwendet, wenn alle anderen<br />

Stellen nicht mehr ausreichen, um eine Zahl darzustellen. Mit einer Stelle können Sie nur die<br />

Zahlen Null und Eins darstellen, mit zwei Stellen bereits die Zahlen Null bis Drei. Mit drei Stellen<br />

sind bereits die Zahlen Null bis Sieben darstellbar. Zur Umrechnung geben Sie jeder Stelle einen<br />

Umrechnungswert. Diese zusammengerechnet ergeben den Dezimalwert. Die erste Stelle hat<br />

dabei den Umrechnungswert 1, die zweite den Wert 2, die dritte den Wert 4 und die vierte den<br />

Wert 8 und so weiter. Es ist leicht erkennbar, dass hier immer das doppelte des vorigen Wertes<br />

eine Rolle spielt. Die fünfte Stelle würde also den Wert 16 haben. Anders ausgedrückt sind die<br />

Umrechnungswerte Zweierpotenzen:<br />

2 0 = 1<br />

2 1 = 2<br />

2 2 = 4<br />

2 3 = 8<br />

Angenommen, Sie müssten die folgende Binärzahl 11<strong>01</strong> in das Dezimalsystem umrechnen, dann<br />

sollten Sie wie gefolgt vorgehen:<br />

Die Zahl besteht aus vier Stellen, deren Wert 8,4,2,1 ist. In diesem Fall ist der Wert 2 nicht<br />

vorhanden. Zusammengerechnet wird also 8, 4 und 1. Das Ergebnis wäre also 13.<br />

1 1 0 1 Binär<br />

2 3 2 2<br />

0 2 0<br />

Umrechnungswert<br />

8 4 0 0 Dezimalwert<br />

Ein weiteres Beispiel für die folgende Zahl 1<strong>01</strong>1:<br />

Die Werte 8, 2 und 1 sind in der Binärzahl enthalten. Die Dezimalzahl wäre demnach 11.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │57


Variablen als Flags<br />

Entities haben bekanntlich nur 8 Flags, was häufig nicht ausreicht. In dem Fall verwenden viele<br />

Anfänger Skills als Flags, indem sie diese auf den Wert 0 oder 1 setzen. Für acht Flags würden auf<br />

diese Weise bereits acht Skills benötigt werden. Das ist Verschwendung, denn bereits ein Skill<br />

reicht für acht Flags aus. Möglich wird das durch Bitoperatoren und dem Wissen über das<br />

Binärsystem. Im Grunde stellt jede Stelle im Binärsystem ein Flag dar, da sie auf 0 oder 1 gesetzt<br />

werden kann. Die Engine selbst macht sich dies beim move_ und trace_mode zunutze, denn im<br />

Grunde sind die beiden "modes" einfach nur Variablen.<br />

Das Setzen von Flags funktioniert sehr einfach. Da jedes Flag eine "Stelle" repräsentiert, müssen<br />

Sie einfach nur den Umrechnungswert dieser Stelle in die Variable einfügen.<br />

Flag1 entspricht 1<br />

Flag2 entspricht 2<br />

Flag3 entspricht 4<br />

...<br />

Der Hintergrund ist einfach, dass jeder Kombination dieser Zahlen einmalig ist und eine Zahl<br />

niemals doppelt auftritt. In den mode-Beispielen werden diese Flags/Zahlen einfach addiert.<br />

Das ist aber nicht ungefährlich. Angenommen, Sie hätten Flag1 aktiviert, dann wäre die Variable<br />

(ich nenne sie "var") var == 1. Sie benutzen var später nochmal und wollen das Flag1 setzen,<br />

wissen aber nicht, ob es bereits gesetzt ist. Mit var += 1 wäre nun var == 2. Das Ergebnis wäre,<br />

dass Flag2 gesetzt ist, Flag1 aber nicht (denn Flag2 entspricht bereits dem Wert Zwei). Sie können<br />

dies nachprüfen, indem Sie trace_mode = ignore_me + ignore_me setzen. Das Ergebnis wird sein,<br />

dass me nicht ignoriert wird, dafür aber you.<br />

Die richtige Art, ein Flag zu setzen, ist der "oder"-Operator. Im folgenden Beispiel ist Flag4, Flag3<br />

und Flag1 gesetzt. Flag3 wird nun auf on gesetzt. Das Ergebnis bleibt gleich:<br />

Input1<br />

Input2<br />

or- result<br />

1<br />

0<br />

1<br />

1 0 1<br />

1 0 0<br />

1 0 1<br />

Es ist also sicherer, wenn Sie den trace_mode mittels or-Operator setzen:<br />

trace_mode = ignore_me | ignore_you | ignore_push;<br />

Hier ist ein Codebeispiel, mit dem sie für eine Variable var ein bestimmtes Flag setzen können.<br />

function SetFlag(var, flag_num) {<br />

if(flag_num == 1) { var |= 1; } // setze Flag1<br />

if(flag_num == 2) { var |= 2; } // setze Flag2<br />

if(flag_num == 3) { var |= 4; } // setze Flag3<br />

if(flag_num == 4) { var |= 8; } // setze Flag4<br />

if(flag_num == 5) { var |= 16; } // setze Flag5<br />

if(flag_num == 6) { var |= 32; } // setze Flag6<br />

if(flag_num == 7) { var |= 64; } // setze Flag7<br />

if(flag_num == 8) { var |= 128; } // setze Flag8<br />

}<br />

Nachdem Sie nun wissen, wie Flags gesetzt werden, sollten Sie wissen, wie Sie überprüfen<br />

können, ob ein Flag gesetzt ist. Dazu verwenden Sie den und-Operator. Er liefert wie bereits<br />

erläutert nur eine 1 für eine Stelle zurück, wenn beide Inputs an dieser Stelle eine 1 haben. In<br />

folgendem Beispiel ist wieder Flag4, Flag3 und Flag1 gesetzt und es soll überprüft werden, ob<br />

Flag3 gesetzt ist:<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │58


Input1<br />

Input2<br />

und result<br />

1<br />

0<br />

0<br />

1 0 1<br />

1 0 0<br />

1 0 0<br />

Das Ergebnis ist also genau der Umrechnungswert des zu prüfenden Flags, falls das Flag gesetzt<br />

ist. Hier ist der Code zum Prüfen eines Flags:<br />

function IfFlag(var, flag_num) {<br />

}<br />

if(flag_num == 1) {<br />

}<br />

if((var & 1) == 1) { return(1); } // Flag1 ist gesetzt<br />

if(flag_num == 2) {<br />

}<br />

if((var & 2) == 2) { return(1); } // Flag2 ist gesetzt<br />

if(flag_num == 3) {<br />

}<br />

if((var & 4) == 4) { return(1); } // Flag3 ist gesetzt<br />

if(flag_num == 4) {<br />

}<br />

if((var & 8) == 8) { return(1); } // Flag4 ist gesetzt<br />

if(flag_num == 5) {<br />

}<br />

if((var & 16) == 16) { return(1); } // Flag5 ist gesetzt<br />

if(flag_num == 6) {<br />

}<br />

if((var & 32) == 32) { return(1); } // Flag6 ist gesetzt<br />

if(flag_num == 7) {<br />

}<br />

if((var & 64) == 64) { return(1); } // Flag7 ist gesetzt<br />

if(flag_num == 8) {<br />

}<br />

if((var & 128) == 128) { return(1); } // Flag8 ist gesetzt<br />

return(0); // Flag ist nicht gesetzt<br />

Ist das Flag gesetzt, gibt die Funktion eine 1 (true zurück), andernfalls eine 0 (false). Die<br />

Anwendung ist simpel:<br />

if(IfFlag(trace_mode,1)) {<br />

}<br />

error("Flag1 der Variable trace_mode ist gesetzt");<br />

Was nun noch fehlt, ist das entfernen eines Flags. Dazu benötigen sie einen weiteren Bit-Operator,<br />

den "Inversen-Operator", oder auch COMPLEMENT operator. Er wird durch ein Tilde (~)<br />

dargestellt. Er invertiert die Bits einer Variable, sodass aus 0 eine 1 und aus 1 eine 0 wird.<br />

Für das Beispiel der Dezimalzahl 5:<br />

var 0 1 0 1<br />

~var 1 0 1 0<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │59


Man könnte sagen, dass alle aktivierten Flags deaktiviert werden und alle anderen aktiviert. Was<br />

nützt Ihnen das, um ein bestimmtes Flag zu deaktivieren? Betrachten Sie folgende Formel:<br />

var &= ~1<br />

In Worten ausgedrückt: Benutze den und-Operator auf die Bit-Inverse von 1.<br />

1 0 0 0 1<br />

~1 1 1 1 0<br />

Hier ist eine beliebige Variable und die Bit-Inverse von 1, die mit dem AND-Operator benutzt<br />

werden:<br />

var 1 1 0 1<br />

~1 1 1 1 0<br />

and-result 1 1 0 0<br />

Das Ergebnis ist tatsächlich, dass das Flag verschwindet. Hier ist der Code:<br />

function RemovFlag(var, flag_num) {<br />

}<br />

if(flag_num == 1) { var &= ~1; } // entfernt Flag1<br />

if(flag_num == 2) { var &= ~2; } // entfernt Flag2<br />

if(flag_num == 3) { var &= ~4; } // entfernt Flag3<br />

if(flag_num == 4) { var &= ~8; } // entfernt Flag4<br />

if(flag_num == 5) { var &= ~16; } // entfernt Flag5<br />

if(flag_num == 6) { var &= ~32; } // entfernt Flag6<br />

if(flag_num == 7) { var &= ~64; } // entfernt Flag7<br />

if(flag_num == 8) { var &= ~128; } // entfernt Flag8<br />

Zu guter letzt...<br />

Es gibt natürlich noch andere Bit-Operatoren wie z.B. XOR – exclusive or – und Kombinationen<br />

von Bitoperatoren. Die genannten reichen aber erstmal aus. Auch die Funktionen sind sehr<br />

unschön geschrieben und könnten ein Stück gekürzt werden. Zum Verständnis sind sie meiner<br />

Meinung nach aber ausreichend bzw. besser geeignet. Wenn Sie ein wenig mit Bitoperatoren<br />

gearbeitet haben, können Sie Zeilen auch direkt eingeben ohne eine große Funktion zu benutzen.<br />

Hier nochmal einige Kurzbeispiele:<br />

var |= 4; // setzt Flag3<br />

var &= ~8; // entfernt Flag4<br />

if(var & 8) { // Flag4 ist gesetzt<br />

}<br />

return(1);<br />

Noch einfacher ist es, wenn Sie die Umrechnungswerte durch Definitionen ersetzen:<br />

define flag_1, 1;<br />

define flag_2, 2;<br />

define flag_3, 4;<br />

define flag_4, 8;<br />

define flag_5, 16;<br />

var |= flag_2; // setzt Flag2<br />

var &= ~flag_3; // entfernt Flag3<br />

if(var & flag_1) { // Flag1 ist gesetzt<br />

return(1);<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │60


}<br />

Ich hoffe, diese Einführung in Bit-Operatoren war verständlich. Kritik und Lob bitte an das <strong>3D</strong>GS-<br />

<strong>Magazin</strong> oder direkt an mk.1@gmx.net<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │61


Möglichkeiten des Physiksystems in Gamestudio<br />

Commercial<br />

Dies ist kein Tutorial.<br />

Vielmehr soll dieser Artikel dazu anregen sich mit dem „beschränkten“ Physiksystem der<br />

Commercial Version zu beschäftigen, was alles andere als langweilig ist.<br />

Viele „träumen“ wohl von der Professional Version, da wäre es doch gut zu wissen, was man von<br />

der Gamestudiophysik so zu erwarten hat.<br />

Vielen ist auch nicht bewußt was man mit einem Physikobjekt alles anstellen kann. Abgesehen<br />

von diversen Spielereien mit Kugeln eignet sich die limitierte Physik für Gleiter, Schiffe, Schlitten<br />

und Bob´s, kurz, alles was gleitet. Man denke an Wintersportarten. Aber auch fiese Fallen und<br />

Kanonenschüsse, Interaktion mit Objekten und Constraints sind möglich. Wegwerfbare<br />

Gegenstände und eine Gravitygun sind ebenso machbar. Geduldsspiele in der Art eines<br />

Kugellabyrinthes, Ballspiele, von Fußball über Golf bis Tennis. In einem Physikobjekt steckt mehr<br />

als man meinen könnte.<br />

Zuerst sollte man betrachten was man mit einem Objekt alles bekommt und welche Eigenschaften<br />

ein Physikobjekt auszeichnen:<br />

• Gravitation<br />

• Ein Schwerpunkt<br />

• Polygongenaue Kollisionserkennung wenn gewünscht<br />

• Events werden nach wie vor ausgelöst<br />

• Es können Kräfte verschiedenster Arten auf das Objekt angewendet werden<br />

• Mehrere Physikobjekte können simuliert werden, allerdings auf Kosten der Performance<br />

• Es kann Beschränkungen (Constraints) mit der „Welt“ geben.<br />

Was kann man nun damit anfangen? Auf ein Physikobjekt können Kräfte ausgeübt werden,<br />

sogenannte Beschleunigungen. Wenn man diese an Events koppelt, können nette<br />

Interaktionsmöglichkeiten herauskommen. Ein Trampolin oder ähnliches müsste z.B. bei Kontakt<br />

eine Kraft auf das Physikobjekt anwenden. Schauen Sie sich dazu eine Skizze an:<br />

Die Kugel ist das Physikobjekt. Sie kommt von links oben im Bogen<br />

angeflogen und trifft auf die „Trampolin“ Entity. Diese erkennt aufgrund eines<br />

Events die Kollision und wendet per „phent_addcentralforce“ eine Kraft in Z-<br />

Richtung (nach oben) auf das Physikobjekt an. Das Resultat ist eine<br />

physikalisch korrekte Bewegung der Kugel, da sie ihre „Eigenrichtung“ von<br />

rechts nach links beibehält. Die Kraft in Z-Richtung wird nur addiert.<br />

Es ist etwas gewöhnungsbedürftig Physikobjekte über Kräfte und nicht über „ent_move“ oder<br />

„c_move“ zu bewegen. Wenn Sie jedoch einmal ein wenig herum experimentiert haben, werden Sie<br />

das System schnell verstehen. Was sie zuerst verstehen müssen ist der Unterschied zwischen<br />

lokalen und globalen Kräften. Globale Kräfte beziehen sich immer auf das Level und seine<br />

Koordinaten. Hiermit können Sie zum Beispiel eine Drift erzeugen, die als Gegenwind wirkt. Lokale<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │62


Kräfte beziehen sich auf die Koordinaten der Entity und sind z.B. für Flugsimulationen recht<br />

hilfreich. So muß man sich nie Gedanken über die Ausrichtung der Entity zu den Levelkoordinaten<br />

machen.<br />

Was bieten uns nun Constraints in einer solch limitierten Umgebung? Zur Anregung wieder eine<br />

Skizze:<br />

Die mittlere „Platte“ ist mit einer Beschränkung zur Welt verbunden. Hier<br />

wäre es „ph_hinge“. Wenn nun der Player auf die Plattform geht, sorgt ein<br />

Event dafür das die Plattform sich bewegt, z.B. durch „phcon_setmotor“. Es<br />

sind auch noch ganz andere Gemeinheiten möglich - denken Sie an Indiana<br />

Jones und die dicke Steinkugel die ihm nachstellt, Pendel und Messer die von<br />

der Decke hängen oder noch labilere Plattformen. Die Arten der möglichen<br />

Beschränkungen sind vielfältig.<br />

Ich selbst habe noch nicht viel Erfahrung mit der Physikengine gesammelt, kann jedoch sagen<br />

dass sie sehr intuitiv ist. Sie werden sehen, es macht Spaß Kräfte auf Objekte auszuüben und die<br />

Auswirkungen zu erfahren. Danach können Sie versuchen mit Constraints zu arbeiten.<br />

Ich hoffe ich konnte Ihnen ein wenig den Mund wässrig machen. Physik in Spielen bietet großartige<br />

Möglichkeiten, und wenn es nur ein Objekt zur selben Zeit ist. Ein Tutorial zum Thema wird noch<br />

folgen.<br />

Grüße,<br />

Quellen zum Thema:<br />

• Aum 25 - Physik Demo<br />

• Aum 37 - Mehrere Physikobjekte mit Commercial<br />

• Aum 47 – Rollem, ein Marble Klon<br />

• Link: http://www.conitec.net/english/gstudio/aum.htm<br />

- Physikengine Forumthread –<br />

Glossar:<br />

B<br />

Torsten „fogman“ Fock fogman@gmx.com<br />

Link: http://www.coniserver.net/ubbthreads/postlist.php?Cat=0&Board=UBB32<br />

Im folgenden werden die im Text hervorgehobenen Begriffe genauer erläutert.<br />

Beschleunigung --> Kräfte<br />

Beschränkungen --> Constrains<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │63


C<br />

E<br />

G<br />

K<br />

P<br />

Constraints<br />

Einfach gesagt sind Constraints Gelenke, welche die Bewegungen der Objekte einschränken. Es<br />

gibt Scharniere (ph_hinge), Kugelgelenke (ph_ball), Schubverbindungen (ph_slider) und<br />

Radachsen (ph_wheel).<br />

Events<br />

Wenn eine Kollision stattfindet können sogenannte Events ausgelöst werden. Die solcherart<br />

gestartete Funktion kann nun z.B. mit Kräften auf das Objekt wirken.<br />

Gravitation<br />

Die Schwerkraft / Gewichtskraft. Hier bietet sich ein Zitat aus dem Gamestudiomanual an: „Die<br />

Erdanziehungskraft ist normalerweise 9.81 m/s², 1 Quant ist normalerweise als 1 Zoll = 2.54cm<br />

definiert. Um die Erdanziehungskraft zu simulieren, muss vecGravity.z bei Standardscalierung auf<br />

(-9.81 * 100 / 2.54) = -386 gesetzt werden.“<br />

Gravitygun<br />

Eine immer wieder gern gestellte Frage ist, ob dies denn mit GS möglich sei. Natürlich muß ich da<br />

sagen, es wird etwas Arbeit sein, aber warum sollte es nicht funktionieren Eine Gravitygun bewegt<br />

Objekte (Möbel, Autos, Gegner), also wirkt sie mit Kräften auf andere Objekte. Genau das, was<br />

eine Physikengine kann ;)<br />

Kollision<br />

Aneinanderstoßen einer Entities mit anderen Objekten.<br />

Kollisionserkennung<br />

Die Gamestudiophysik hat den großen Vorteil der polygongenauen Kollisionserkennung.<br />

Da diese sehr rechenaufwändig ist, gibt es noch andere Kollisionshüllen. Kugel-,<br />

Quader- und Zylinderform sind möglich.<br />

Kollisionshülle<br />

Die Hülle um das Physikobjekt welche bestimmt ab wann eine Berührung als Kollision zählt.<br />

Kräfte lokal / global<br />

Kräfte sind z.B. lineare Beschleunigung und Drehmomente. Lokale Kräfte beziehen sich auf die<br />

Koordinaten des Objekts, globale Kräfte beziehen sich auf die Levelkoordinaten.<br />

Polygongenaue Kollisionserkennung --> Kollisionserkennung<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │64


S<br />

W<br />

Schwerpunkt<br />

Der Schwerpunkt beschreibt den „Nullpunkt“ eines Objektes. Wenn Sie das Objekt an ihm<br />

aufhängen würden, könnten Sie es in jede Richtung drehen ohne das es sich in seine alte Position<br />

zurückbewegt. Man bezeichnet diesen Zustand auch als „indifferent“, im Gegensatz zu „labil“<br />

(kopflastig, z. B. wenn man einen Stock auf einem Finger balanciert) und „stabil“ (wenn der Stock<br />

wie ein Pendel hängt). Ein Stehaufmännchen hat einen sehr niedrigen Schwerpunkt, es ist unten<br />

schwerer als oben. Ein Fernsehturm hat einen hohen Schwerpunkt, er ist oben schwerer als unten.<br />

In der Gamestudiophysik ist immer der Mittelpunkt einer Entity der Schwerpunkt. (Nicht sein Origin<br />

/ Nullpunkt in MED/WED !)<br />

Welt<br />

Etwas unglücklich gewählt, beschreibt dieser Begriff die Umgebung, also das Level. Wenn Objekte<br />

also eine Beschränkung mit der „Welt“ eingehen, so ist das als ob sie ein Scharnier in eine Straße<br />

betonieren – die Straße wird sich nicht bewegen, wohl aber das Teil welches Sie am anderen Ende<br />

des Scharniers befestigen.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │65


Inhalt:<br />

Formationsanordnungen in einem <strong>3D</strong> Spiel<br />

von Dieter Meier aka ARAS14<br />

• Vorbereitung des Levels und des Mainskriptes<br />

• Änderung des Mainskriptes<br />

• Kamera in der "camera.wdl"<br />

• Funktion "move_view()"<br />

• Bewegung der Führungsfigur in der "Bewegungs.wdl"<br />

• Funktion "get_target()"<br />

• Funktion "gravity_entity()"<br />

• Funktion "move_entity()"<br />

• Funktion "chef_player_move()"<br />

• Aktion "haupt_player"<br />

• Formation der Entity´s in der "Formation.wdl"<br />

• Aktion "entitys"<br />

• Funktion "entity_formation"<br />

• Funktion "pos1_ent"<br />

Für die unter Ihnen die zu wenig Zeit haben selbst ein Level für das Tutorial zu bauen, habe ich das<br />

Ganze schon vorbereitet. Sie finden unter der unten genannten URL.Adr. ein Beispiellevel mit den<br />

dazugehörigen Skripten. Ich wünsche Ihnen viel Spaß dabei.<br />

http://space<strong>01</strong>.annih.de/DemoFormation.zip<br />

Einführung:<br />

Ich möchte in diesem ersten Tutorial auf die Grundzüge einer Formationsanordung und deren<br />

Bewegung eingehen. Desweiteren werden wir eine isometrische Kamera programmieren und das<br />

Skript für eine Playerbewegung mit Hilfe des Cursors realisieren.<br />

Solche Formations Anordnungen werden hauptsächlich in Strategiespielen Anwendung finden. Es<br />

gibt bestimmt noch anderen Möglichkeiten so etwas zu realisieren. Ich möchte Ihnen eine davon<br />

vorstellen.<br />

Vorbereitung des Levels und des Mainskriptes<br />

Bauen Sie ein Level nach Ihren Wünschen oder verwenden Sie das mitgelieferte, das ich für Sie<br />

schon vorbereitet habe. Generieren Sie von Ihrem Level ein Mainskript. Wenn Sie das Demolevel<br />

verwenden brauchen Sie sich diese Arbeit nicht mehr machen, da ich für Sie das Skript schon<br />

vorbereitet habe.<br />

Änderung des Mainscriptes<br />

Öffnen Sie das Mainskript Ihres Levels und entfernen Sie die Include Dateien nach der<br />

"particle.wdl" Datei. Oder klammern Sie diese wie im unteren Beispiel einfach aus. Diese Dateien<br />

benötigen wir für unsere Formationsanordungen nicht. Die ganzen Änderungen im Mainskript<br />

beziehen sich noch auf die alten Templates. Bei Verwendung der Neuen müssen Sie das Skript<br />

dementsprechend anpassen.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │66


// The INCLUDE keyword can be used to include further WDL files,<br />

// like those in the TEMPLATE subdirectory, with prefabricated actions<br />

include ;<br />

include ;<br />

include ; // must be inserted before doors and weapons<br />

include ; // remove when you need no particles<br />

/*<br />

include ; // remove when you need no doors<br />

include ; // remove when you need no actors<br />

include ; // remove when you need no weapons<br />

include ; // remove when you need no fighting<br />

//include ; // include when doing an adventure<br />

include ; // remove when you need no lens flares<br />

*/<br />

Was Sie noch ausklammern müssen wenn Sie ein neues Skript von Ihrem Level generiert haben<br />

sind die Anweisung "lensflare_start();" und "move_view_cap = 1;". Suchen Sie nach folgenden<br />

Zeilen und klammern Sie diese aus.<br />

// initialize lens flares when edition supports flares<br />

ifdef CAPS_FLARE;<br />

endif;<br />

//lensflare_start();<br />

// use the new 3rd person camera<br />

//move_view_cap = 1;<br />

Schreiben Sie ans Ende der Funktion "main()" noch den Befehl "mouse_toggle();", damit der<br />

Cursor sofort nach Laden des Levels sichtbar wird.<br />

// client_move(); // for a possible multiplayer game<br />

// call further functions here...<br />

mouse_toggle();<br />

}<br />

Als nächstes includieren Sie bitte die zwei Dateien "Bewegung.wdl" und "Formation.wdl". Diese<br />

zwei Dateien werden später unsere Skripte, wie der Name schon sagt, für die Formation und die<br />

Bewegung enthalten.<br />

Sollten Sie die beigestellten Skripte verwenden, müssen Sie im Skript "DemoFormation.wdl"<br />

unbedingt den Verweis auf den Template-Ordner hier:<br />

path "D:\\PROGRAMME\\GSTUDIO6\\template"; auf den Path Ihres Template Ordners<br />

umschreiben.<br />

Kamera in der "camera.wdl"<br />

Die Kamera sollte uns sowohl einen Einblick über das ganze Szenario, als auch eine detailierte<br />

Ansicht bieten, was bedeutet sie sollte auf jeden Fall zoombar sein. Die Veränderung des<br />

Drehwinkels (Pan-Winkel) und des Schwenkwinkels (Tilt-Winkel) sollten wir auch nicht vergessen<br />

um später unsere Einheiten nicht aus den Augen zu verlieren. Die Zoom-, Dreh- und<br />

Schwenkbewegungen der Kamera werden wir im nächsten Tutorial programmieren und ausführlich<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │67


esprechen. In diesem hier werden wir uns mit einer einfachen festen Kamera begnügen. Legen<br />

Sie nun eine WDL-Datei an und nennen sie"camera.wdl". Sie beinhaltet die Steuerung der Kamera.<br />

Beginnen wir mit den Variablen für die Kamera die man benötigt.<br />

var camera_pan = 0; // Winkel der Kamera<br />

var camera_dist = 250; // Abstand zum Player<br />

var camera_z_pos = 800; // Höhe der Kamera<br />

Damit hätten wir schon alle Variablen die wir für die "camera.wdl" benötigen. Was auch noch sehr<br />

hilfreich ist, wäre die Definition aller Funktionen die im dazugehörigen Skript vorkommen. Ich<br />

bevorzuge dies immer, um zu vermeiden das eine Funktion aufgerufen wird, die vorher noch nicht<br />

deklariert worden ist und gehe so einer Engine Fehlermeldung, die daraufhin bestimmt kommen<br />

wird aus dem Weg. Demzufolge schreiben wir nach den Variablen die Definition der Funktionen. In<br />

diesem Fall haben wir nur eine Funktion zum Definieren.<br />

function move_view();<br />

Funktion "move_view()"<br />

Beginnen wir nun mit der Funktion "move_view()". Es umfaßt die eigentlich Bewegung der Kamera.<br />

function move_view()<br />

{<br />

zugehörigen<br />

}<br />

camera.genius = player; // Entity wird unsichtbar wenn die Kamera die<br />

// Grenzen berührt<br />

// Berechnung X-Koord. Kamera<br />

camera.x = player.x + (camera_dist * sin(camera_pan));<br />

// Berechnung Y-Kood. Kamera<br />

camera.y = player.y + (camera_dist * cos(camera_pan));<br />

camera.z = player.z + camera_z_pos; // Berechnung Höhe der Kamera<br />

vec_diff(temp,player.x, camera.x);<br />

vec_to_angle (temp,temp);<br />

camera.pan = temp.pan; // Kamera Pan-Wert<br />

camera.tilt = temp.tilt; // Kamera Tilt-Wert<br />

Die erste Zeile der Funktion bewirkt das der Player unsichtbar wird sobald die Kamera die Grenzen<br />

der Entity berührt. Was in unserem Fall aber nicht auftreten wird. Zeile Zwei und Drei geben die<br />

Berechnung der x- und y-Koordinaten der Kamera bezogen auf die Weltkoordinaten an. Ich will<br />

hier nicht weiter auf diese Winkelberechnungen eingehen, da es hier den Rahmen wohl sprengen<br />

würde. Hierzu gibt es auf der Website von Grimber ein sehr ausführliches Tutorial von "Evelyn<br />

Boo". Nur soviel sei gesagt das wir mit den Angaben in der Klammer "(camera_dist *<br />

sin(camera_pan))" die x-Koordinate unserer Kameradistanz berechnen und mit der Anderen die y-<br />

Koordinate. Die dritte Zeile beinhaltet die Berechnung der Kamerahöhe. In den darauffolgenden<br />

Zeilen wird einmal der Vektor von der Kamera zum Player berechnet und mit "vec_to_angle" der<br />

Winkel dieses Vektors bestimmt. Danach werden die Pan- und Tilt-Winkelder Kamera danach<br />

ausgerichtet. So das erste Skript wäre nun vollendet. Wenden wir uns nun schwierigeren Dingen<br />

zu.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │68


Bewegung der Führungsfigur in der "Bewegungs.wdl"<br />

Öffnen Sie eine weitere WDL-Datei und geben Sie ihr den Namen "Bewegung.wdl". Diese Datei<br />

beinhaltet alle Funktionen die sich mit der Bewegung der Führungsfigur, in diesem Fall der Player-<br />

Entity, befassen.Sollten Ihnen die Funktionen "chef_player_move" bekannt vorkommen ist das<br />

durchaus möglich. Sie bezieht sich im Großen und Ganzen auf das sehr gute diablo-Script aus<br />

einem Aum-Heft. Sie wurde von mir überarbeitet und angepaßt. Beginnen wir wieder mit den<br />

benötigten Variablen.<br />

//// Variablen<br />

var vecfrom;<br />

var vecto;<br />

var my_target;<br />

var ziel_pos;<br />

var force;<br />

var friction;<br />

var dist[3];<br />

var abs_dist[3];<br />

//// Definitionen der Skill´s<br />

define _force, skill36;<br />

define _vz_entity,skill45; // Geschwindigkeit vertikal der Entity<br />

define _v_entity,skill47; // Geschwindigkeit horizontal der Entity<br />

define ziel,skill48; // Freigabe Zielposition 0 = Aus, 1 = An<br />

Als nächstes rufen wir wieder alle Funktionen auf um eine etwaige Fehlermeldung zu umgehen.<br />

function get_target();<br />

function gravity_entity();<br />

function move_entity();<br />

function chef_player_move();<br />

Funktion "get_target()"<br />

Jetzt beginnen wir mit dem ersten Skript. Es wird die Funktion "get_target()" sein. Mit deren Hilfe<br />

wir dem Player durch Anklicken im Level ein Ziel zuweisen.<br />

function get_target() // Zielposition<br />

{<br />

vecfrom.x = mouse_pos.x; // X-Position des Cursors<br />

vecfrom.y = mouse_pos.y; // Y-Position des Cursors<br />

vecfrom.z = 10;<br />

vec_set(vecto,vecfrom);<br />

vec_for_screen(vecfrom,camera); // Vektor bekommt Bildschirmkoordinaten<br />

vecto.z = 5000;<br />

vec_for_screen(vecto,camera); // Vektor bekommt Bildschirmkoordinaten<br />

trace(vecfrom,vecto); // trace von der Kamera auf angeklickten Punkt<br />

vec_set(my_target,target);<br />

vec_set(ziel_pos,target);<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │69


vec_sub(ziel_pos,player.x); // Bestimmung des Richtungsvektors<br />

vec_to_angle(player.pan,ziel_pos); // Drehung der Playerentity in Richtung der<br />

Zielpos.<br />

}<br />

player.tilt = 0;<br />

player.ziel = 1; // Spieler hat Zielposition zugewiesen<br />

Zeile 1-7 beziehen sich auf die Berechnung der x- und y-Position des Cursors und Umrechnung<br />

dieser Koordinaten mit Hilfe des "vec_for_screen" Befehls in einen Vektor. Diese Vektoren<br />

benötigen wir um mit dem "trace" Befehl von einem gedachten Punkt, direkt hinter dem Bildschirm<br />

hinein ins Level zutracen und zwar 5000 Quants hinter den Bildschirm. Der Schnittpunkt mit der<br />

Levelgeometrie wird im "target" Vektor gespeichert und gibt uns somit unseren Zielpunkt an.<br />

Danach bestimmen wir den Richtungsvektor von der Playerposition zur Zielposition mit "vec_sub"<br />

und anschließend drehen wir noch den Player in Richtung der Zielposition mit Hilfe des Befehls<br />

"vec_to_angle".<br />

Funktion "gravity_entity()"<br />

Folgt nun eine Funktion die verhindert das eine Entity aus irgendwelchen unvorhersehbaren<br />

Gründen in der Luft schwebt ohne herunter zufallen. Die "gravity_entity" Funktion.<br />

function gravity_entity()<br />

{<br />

vec_set (temp.x,nullvector);<br />

vec_set(temp,my.x);<br />

temp.z -=4000;<br />

trace_mode = ignore_me + ignore_sprites + use_box + ignore_models;<br />

result = trace(my.x,temp); // Trace auf den Boden<br />

if (result > 5)<br />

{<br />

}<br />

else<br />

{<br />

}<br />

force.z = -5; // Schwerkraft<br />

friction = 0.1;//Reibung<br />

force.z = -0.5 * result; // Boden-Elastizität<br />

friction = 0.5; // Bodenreibung<br />

my._vz_entity = time * force.z + max(1-time * friction,0) * my._vz_entity; //<br />

Geschw. vert.<br />

}<br />

abs_dist.z = time * my._vz_entity; // Distanz vertikal<br />

Die erste Zeile verwenden wir dazu um den Vektor "temp" zu löschen, also alle Werte auf Null zu<br />

setzen. Danach überschreiben wir den Vektor mit den Koordinaten der Entity. Nachdem wir der<br />

"temp.z" Variablen einen Wert 4000 Quants unter der Entity zugewiesen haben, führen wir einen<br />

"trace" von der EntityPosition zu einem Punkt 4000 Quants darunter durch. Stößt der Trace auf ein<br />

Hindernis wird diese Entfernung in der Variablen "result" gespeichert und dient uns somit zur<br />

weiteren Berechnung. Ist das Ergebnis der Result-Variablen größer als 5 Quants setzen wir die<br />

Schwerkraft auf den Wert -5 und die Reibung, da wir uns ja folglich in der Luft befinden, auf einen<br />

sehr niedrigen Wert hier 0.1. Sollte das Gegenteil der Fall sein und unser "result" ist kleiner als 5<br />

oder hat gar einen negativen Wert, was bedeuten würde, daß die Entity schon in den Boden<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │70


eingedrungen ist, kommt unsere Formel "force.z = -0.5 * result" zum Einsatz. Sollte das Ergebnis<br />

unserer Messung negativ sein wird mit dieser Formel der "force.z" Wert, also die Bewegung<br />

vertikal, wieder auf einen positiven Wert gebracht, da ja "Minus * Minus" bekanntlich "Plus" ist.<br />

Das bedeutet unsere Entity macht wieder eine Bewegung noch Oben aus dem Boden heraus . Die<br />

letzten Zeilen bewirken einen stetigen Anstieg dieser Geschwindigkeit und deren Berechnung der<br />

vertikalen Distanz der Entity.<br />

Funktion "move_entity()"<br />

Bewegungsfunktion um Entity mit Hilfe des relativen- und absoluten Vectors zu bewegen.<br />

function move_entity()<br />

{<br />

my._v_entity = time * force.x + max(1-time*0.7,0) * my._v_entity;<br />

//Geschwindigkeit vor.<br />

}<br />

dist.x = time * my._v_entity; //Distanz vorwärts<br />

dist.y = 0;<br />

dist.z = 0;<br />

move_mode = ignore_passable + glide;<br />

result = ent_move(dist,abs_dist); // Bewege den Player<br />

Die ersten beiden Zeilen beziehen sich auf die vorwärts Bewegung der Entity, bezogen auf ihren<br />

"force.x"Wert. Hierfür benötigen wir nur die Variable "dist.x" da wir mit der Entity nur eine relative<br />

Bewegung ausführen, bezogen auf die Richtungswinkel der Entity. Somit kann man die Werte<br />

"dist.y" und "dist.z"auf Null setzen. Danach geben wir noch den "move_mode" an und bewegen<br />

dann die Entity mit "ent_move".<br />

Funktion "chef_player_move()"<br />

In dieser Funktion finden wir die "vec_dist" Berechnung zum Zielpunkt und die Aktivierung der<br />

Funktionen "gravity_entity" und "move_entity".<br />

function chef_player_move()<br />

{<br />

while(1)<br />

{<br />

}<br />

if(player.ziel == 1) // Player hat eine Zielposition<br />

{<br />

// Nur Bewegung wenn Distanz zum Ziel größer 35 Quants ist<br />

while(vec_dist(player.x,my_target.x) > 35)<br />

{<br />

force = my._force * 12; // Geschwindigkeitsberechnung des Player´s<br />

// Vorzeitiger Abbruch der Bewegung beim drücken der rechten Maustaste<br />

}<br />

if(mouse_right == 1){wait(1);player.ziel = 0;break;}<br />

gravity_entity(); // Sprung zur Gravitationsfunktion der Entity<br />

move_entity(); // Sprung zur Bewegungsfunktion der Entity<br />

wait(1);<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │71


}<br />

wait(1);<br />

}<br />

Diese Funktion wird stetig ausgeführt. Danach wird mit "if(player == 1)" überprüft ob der Player<br />

eine Zielposition hat. In diesem Fall wird eine zweite Schleife gestartet, die testet ob der Player<br />

mehr als 35 Quants vom Zielpunkt entfernt ist. Trifft dies zu wird die Geschwindigkeit des Players<br />

gesetzt und die Funktionen "gravity_entity" und "move_entity" ausgeführt. Mit Hilfe der Zeile<br />

"if(mouse_right == 1)" wird der Zielbefehl durch drücken der rechten Maustaste wieder<br />

abgebrochen. Sollte die Entfernung weniger als 35 Quants betragen wird die Schleife beendet und<br />

erst wieder gestartet wenn der Abstand zwischen Ziel und Player größer geworden ist.<br />

Aktion "haupt_player"<br />

Diese Aktion teilen wir in WED unserer Entity zu. Sie wird unseren Player darstellen. Alle anderen<br />

Entities der Formation werden sich um diese Entity sammeln und ihr folgen.<br />

action haupt_player<br />

{<br />

}<br />

player = me;<br />

my._force = 1; // Grundgeschwindigkeit des Players<br />

chef_player_move();<br />

while(1)<br />

{<br />

}<br />

move_view(); // Aktivierung der Kamerafunktion<br />

wait(1);<br />

Als Erstes weisen wir dem "me"-Pointer den "player"-Pointer zu. Jetzt können wir diesen Pointer in<br />

allen anderen Funktionen verwenden, ohne eine "Empty Pointer" Fehlermeldung zu bekommen.<br />

Danach geben wir der Entity eine Grundgeschwindigkeit mit "my._force = 1" und starten<br />

anschließend unsere "chef_player_move()" Funktion. Es wird noch eine Schleife gestartet in der wir<br />

die Kamerafunktion aufrufen. Damit stellen wir sicher das uns die Kamera auch folgt, da diese<br />

Funktion immer durchlaufen wird. Wie Sie bestimmt schon bemerkt haben wird unsere<br />

"get_target" Funktion noch nirgends aufgerufen. Sie soll ja nur beim Drücken der linken Maustaste<br />

aktiviert werden, darum realisieren wir das Ganze mit einem einfachen Befehl.<br />

// Linke Maustaste aktiviert die Zielposition für den Player<br />

On_mouse_left get_target;<br />

So damit hätten wir schon die ersten Teile unseres Tutorials geschafft, lassen Sie uns jetzt zum<br />

eigentlichen Hauptteil kommen. Die Skripte für die Entities die unserem Player in einer Formation<br />

folgen sollen.<br />

Formation der Entities in der "Formation.wdl"<br />

Was brauchen wir dazu? Einmal natürlich Entities die sich immer in der gleichen Formation hinter<br />

dem Player sammeln. Wir benötigen also bestimmte Fix-Punkte die wir am Anfang festlegen. Das<br />

Ganze realisieren wir über ein Array aus dem wir diese Parameter auslesen. Diese Parameter<br />

werden immer unsere Zielposition sein. Um diese Position festzulegen benötigen wir noch eine<br />

Hilfsentity,in der wir diese Parameter speichern und die sich immer mit dem Player bewegt. Auf<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │72


diese Weise können wir später der Hilfsentity diverse Formationen vorgeben. Nun brauchen wir nur<br />

noch unsere Folgeentity, ich nenne sie einmal unseren Soldaten. Unser Soldat richtet sich nach der<br />

Hilfsentity aus und läuft auf sie zu. Nun wollen wir das Ganze einmal in ein hoffentlich lauffähiges<br />

Skript umwandeln.Beginnen wir wieder mit unseren Variablen und Definitionen.<br />

//// Target MDL<br />

string mace_mdl = ; // Hilfsentity<br />

//// Variablen<br />

var i; // Array Index<br />

var position[8] = -100,-100,-100,100,-200,-200,-200,200; // Array<br />

//// Definitionen der Skill´s<br />

define x_pos,skill30; // x_pos der Hilfsentity<br />

define y_pos,skill31; // y_pos der Hilfsentity<br />

define z_pos,skill32; // z_pos der Hilfsentity<br />

define pos_target,skill36; // Zielposition für Soldaten<br />

//// Funktionen<br />

Aktion "entitys"<br />

function entity_formation(); // Steuerung des Soldaten<br />

function pos1_ent(); // Steuerung der Hilfsentity<br />

Als Erstes beginnen wir mit der Aktion "entitys", hier wird die Funktion der Soldaten aufgerufen. Es<br />

bedarf wohl nicht mehr Erklärung.<br />

action entitys<br />

{<br />

}<br />

my.entity_force = 15; // Festlegung der Geschwindigkeit<br />

entity_formation(); // Aufruf der Funktion<br />

Funktion "entity_formation"<br />

Nun das Skript für die Steuerung des Soldaten. Ich werde Ihnen zuerst das Skript vorstellen und<br />

Ihnen anschließend die Erklärung für einzelne Befehle des Skriptes liefern.<br />

function entity_formation()<br />

{<br />

while(player == null){wait(1);} // Erst weiter wenn Player erstellt ist<br />

my.x_pos = player.x + position[i]; // x_pos der Hilfsentity<br />

i += 1;<br />

my.y_pos = player.y + position[i]; // y_pos der Hilfsentity<br />

i += 1;<br />

you = ent_create(mace_mdl,my.x_pos,pos1_ent); // Hilfsenetity<br />

my.skill40 = handle (you); // you-Pointer abspeichern<br />

while (1)<br />

{<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │73


}<br />

you = ptr_for_handle(my.skill40); // you-Pointer zurück holen<br />

vec_set(temp,you.x);<br />

trace_mode = ignore_models + ignore_sprites + ignore_passents + use_box;<br />

trace(my.x,temp); // Trace zur Hilfsentity<br />

vec_set(my.pos_target,target);<br />

vec_diff(temp,target,my.x); // Zielvector ermitteln<br />

vec_to_angle(my.pan,temp); // Soldat zum Ziel drehen<br />

my.tilt = 0;<br />

if(vec_dist(my.x,my.pos_target) > 35)<br />

}<br />

wait(1);<br />

}<br />

{<br />

force.x = 5; // Geschwindigkeit des Soldaten<br />

vec_diff(temp,my.pos_target,my.x);<br />

vec_to_angle(my.pan,temp); // Zur Zielposition drehen<br />

my.tilt = 0;<br />

gravity_entity(); // Gravitation<br />

move_entity(); // Bewegen des Soldaten<br />

Beginnen wir mit der ersten Zeile "while(player == null){wait(1);}", wir warten so lange bis der<br />

Player erstellt ist, um eine "Empty Pointer" Fehlermeldung zu umgehen. In den nächsten vier<br />

Zeilen werden die Parameter aus dem Array ausgelesen und in den Variablen "my.x_pos" und<br />

"my.y_pos" gespeichert. Als nächstes erstellen wir die Hilfsentity an den vorher ausgelesenen<br />

Positionen und weisen ihr den "you" Pointer zu. Das Ganze speichern wir mit Hilfe eines "handle" in<br />

dem "skill.40" unseres Soldaten. Den "you" Pointer benötigen wir später noch, um immer zu<br />

wissen welche Hilfsentity zu welchem Soldaten gehört. Nun befinden wir uns wieder in einer<br />

Schleife, dort wird der "you" Pointer ausgelesen und mit seiner Hilfe ein "trace" vom Soldaten zur<br />

Hilfsentity ausgeführt. Das Ziel wird im "target" Vektor gespeichert und anschließend der Soldat in<br />

Richtung des Ziels gedreht. Nun springen wir wieder in eine "if" Anweisung, in der wird der<br />

Abstand zu unseren Ziel berechnet. Ist die Entfernung größer als 35 Quants wird die<br />

Geschwindigkeit des Soldaten auf "5" gesetzt, nochmals der Richtungsvektor berechnet und der<br />

Soldat gedreht. Dann wird die Gravitation und die Bewegung des Soldaten aufgerufen.<br />

Funktion "pos1_ent"<br />

In dieser Funktion befinden sich alle Bewegungsbefehle der Hilfsentity.<br />

function pos1_ent()<br />

{<br />

my.passable = on; // Mache mich passierbar<br />

my.invisible = on; // Mache mich unsichtbar<br />

vec_diff(temp,my.x,player.x); // Abstandsvektor zum Player<br />

vec_set(my.x_pos,temp);<br />

while(1)<br />

{<br />

vec_set(temp,my.x_pos);<br />

vec_add(temp,player.x); // Abstandsvektor und Playervektor addieren<br />

vec_set(my.x,temp); // Hilfsentity zum Player ausrichten<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │74


}<br />

}<br />

wait(1);<br />

Als Erstes wird die Hilfsentity passierbar und unsichtbar geschalten, daß sie für den Soldaten kein<br />

Hindernis darstellt. Danach wird der Abstandsvektor zum Player berechnet, daß die Entity immer in<br />

der gleichen Entfernung zum Player steht. In der "while" Schleife wird stetig dieser Abstand zu den<br />

Koordinaten des Players addiert und die Hilfsentity dementsprechend bewegt. Rufen Sie nun Ihr<br />

Level auf und setzen Sie mehrere Entities in Ihr Level. Der Führungsentity weisen Sie die Aktion<br />

"haupt_player" zu und den Entities die ihm folgen sollen die Aktion "entitys". Sollten Sie alles<br />

richtig gemacht haben müßte es so aussehen wie auf diesem Screenshot. Die Soldaten laufen zum<br />

Player und stellen sich in Keilformation hinter ihm auf.<br />

So, wir sind nun am Ende des Tutorial angekommen. Ich hoffe es hat Ihnen etwas geholfen. Wenn<br />

Sie jetzt sagen,"aber da fehlt ja noch Einiges.", dann haben Sie recht. In einem der nächsten<br />

Tutorials werden wir die Kamera ausbauen. Sie wird zoom-, dreh- und schwenkbar werden,<br />

desweiteren werden sich die Soldaten dann auch nach dem Pan-Winkel des Player bewegen und<br />

nicht wie hier nur geradlinig. Wir werden auch versuchen mehrere Formationen anzulegen und<br />

abzuspeichern und wieder aufzurufen. Auch die Animation und Kollisionsüberwachung fehlt noch,<br />

genauso werden wir auch noch ein Sprite für die Zielpositionen einbinden. Aber wie schon gesagt<br />

das wird noch in späteren Tutorials kommen.<br />

Für Fragen oder Kommentare stehe ich gerne zur Verfügung.<br />

Unter<br />

aras_game@chefmail.de<br />

können Sie alles in Bezug auf dieses Tutorial loswerden.<br />

Dann bis zum nächsten Tutorial Ihr<br />

Dieter "ARAS14" Meier<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │75


Interview... mit Sebastian Leopold (Xexes)<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Im Rahmen eines der Projekte, an denen Du beteiligt warst, hast Du einige Grafik-Funktionen<br />

entwickelt. Was war der Hauptgrund für diese Arbeit? Was fehlte euch an A6?<br />

Sebastian Leopold:<br />

Durch die Einschränkung auf die Commercial Edition von A6 konnten wir Features wie „render-totexture“,<br />

welches für unser Projekt unerlässlich war, nicht nutzen. Die Grafikfunktionen wurden<br />

also aus der Not geboren. Als der Grundstein dafür dann einmal gelegt war, wollten wir auch noch<br />

andere Features verwenden, die wir selbst einbauen mussten, da <strong>3D</strong>GS keine Möglichkeiten dafür<br />

bereitstellte.<br />

Dazu zählen beispielsweise Spiegel und Post-Processing.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Kannst Du uns eine kleine Übersicht von Funktionen geben, die Du in diesem Rahmen eingebaut<br />

hast?<br />

Sebastian Leopold:<br />

Natürlich:<br />

- Spiegel<br />

- Wasser-Renderer<br />

- Sky-Renderer<br />

- A6 Mesh-Renderer<br />

- Texturverwaltung mit HDR-Unterstützung<br />

- PostProcessing Effekte<br />

- Softshadows<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Das klingt sehr interessant. Kannst Du einige Worte zum Sky- und Mesh-Renderer schreiben?<br />

Sebastian Leopold:<br />

Der Sky-Renderer ist recht einfach aufgebaut. Es ist eigentlich nur eine Klasse für eine Skybox, die<br />

sich in der Render-Liste befindet. Man braucht jedoch nicht für jeden Sky ein Modell und auch<br />

keine unnötigen Definitionen eines Skies in C-Script. Es reicht aus, einfach eine Textur zu laden<br />

und sie zuzuweisen. Das ganze geht in 6 Zeilen Code.<br />

Der Mesh-Renderer verwendet das Sylex 3.0 Effektsystem und zeichnet <strong>3D</strong>GS Modelle bzw.<br />

Entities. Dadurch wird es möglich Render-Targets sehr schnell auf Modelle zu transferieren<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Du hast das Sylex 3.0 in der aktuellen Version mit Quellcode zur Verfügung gestellt und gut<br />

dokumentiert. Die User waren sehr beeindruckt. Willst Du irgendwann an dem System weiter<br />

arbeiten oder wirst Du nur hin und wieder mal schauen, was die Nutzer damit anstellen?<br />

Sebastian Leopold:<br />

Ich habe es mit Sourcecode veröffentlicht damit die User es selbst weiter entwickeln können. Ich<br />

selbst werde nichts mehr daran machen.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Gibt es schon weitere Pläne in Sachen Spiele-Entwicklung bei Dir?<br />

Sebastian Leopold:<br />

Naja - aufgeben werde ich nicht. Es gibt aber auch noch keine konkreten Pläne. Ich habe aber<br />

mehrere Angebote von Entwicklerteams, dort als Programmierer zu arbeiten. Vielleicht entwickle<br />

ich aber auch eine eigene <strong>3D</strong>-Engine.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │76


<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Du warst mit Sylex sehr erfolgreich. Warum setzt Du dort nicht an und erstellst ein kommerzielles<br />

Plugin? Im Forum gab es einige Stimmen, die bereit wären, dafür zu zahlen.<br />

Sebastian Leopold:<br />

Ich möchte eigentlich nicht mehr mit A6 arbeiten, da mir die Engine zu viele Einschnitte macht.<br />

Außerdem ist es einfacher, eine Engine von Grund auf zu entwickeln, als ein Plugin für eine bereits<br />

Bestehende zu erstellen. Wenn ich eine neue Engine programmiere, soll sie auf RTS-Spiele<br />

optimiert werden.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Ja, das können sicher einige Leute verstehen. Dennoch wird die Community leider ein sehr<br />

talentiertes Mitglied weniger haben.<br />

Gibt es Tipps, die Du den Lesern geben kannst, bezüglich deren Projekte und Team-Management,<br />

sodass sie aus euren Erfahrungen und Fehlern lernen können?<br />

Sebastian Leopold:<br />

Es sollte immer festgelegt sein, welches Aufgabengebiet welches Teammitglied hat. Des Weiteren<br />

halte ich es für sehr sehr wichtig, sich zuerst eine funktionierende Testumgebung aufzubauen. In<br />

meinen Projekten war ich meistens der einzige Programmierer. Oft kam es vor, dass Leveldesigner<br />

versucht haben, die Skripte nach Ihren Wünschen selbst zu verändern. Das bringt aber nichts. Ein<br />

zentrales Portal für alle Mitglieder, wie ein Forum, ist also Pflicht.<br />

Davon abgesehen kann ich eigentlich nur raten, dass man ein Quellenverzeichnis führt, in welchem<br />

man auflistet, wo man welche Textur her hat. Einheitliche Namensgebungen erleichtern die Arbeit<br />

und zum Thema Team-Management wird noch etwas kommen, da dürft ihr euch mal überraschen<br />

lassen.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Wirst Du der Community noch eine Weile erhalten bleiben?<br />

Sebastian Leopold:<br />

Na sicher, Unkraut vergeht nicht!<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Vielen Dank für das Interview.<br />

Sebastian Leopold:<br />

Ich Danke !<br />

Das Interview wurde von Frank Geppert im Auftrag des <strong>3D</strong>GS-<strong>Magazin</strong>s durchgeführt.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │77


Interview... Martin (SFMAT4) und Timo (TripleX)<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

An welchen Projekten arbeitet Ihr zur Zeit?<br />

zu ihren derzeitigen Projekten<br />

Martin:<br />

Defender Competition Demo Level und am Material Editor. Ich helfe Harry Potter noch bei seinem<br />

Mittelalter-Projekt<br />

Defender Competition wird ein Frist Person Ego Shooter ähnlich der UT-Serie. Mit dem Unterschied,<br />

das hier nicht Mann gegen Mann antritt, sondern der Spieler ein Level gegen anströmende<br />

Gegnerhorden verteidigen muss. Dabei kann er Geschütze aufstellen (und bedienen) oder Söldner<br />

anheuern.<br />

Der Material Editor (oder wahrscheinlich GameEdit) wird ein Tool mit dessen Hilfe der User in der<br />

Engine weit reichende Änderungen vornehmen kann.<br />

Bei beiden arbeite ich eng mit TripleX zusammen, wobei Trip fast alle Skript-technischen Aufgaben<br />

übernimmt. Ich erstelle sämtliche Grafiken und Effekte.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Wenn ich das richtig verstehe, dann ist doch der Material-Editor schon weit mehr als nur ein<br />

Material-Editor. Wie weit wollt ihr mit dem Tool gehen?<br />

Martin:<br />

Ich denke wir werden ihn soweit ausbauen, wie es für interne Änderungen im Spiel sinnvoll ist,<br />

und ergänzen das, was von den 3dgs Usern gewünscht wird.<br />

Timo:<br />

Da ich die letzten 2 Monate sehr intensiv am Map Material-Editor programmiert habe, ist nun<br />

tatsächlich schon sehr viel mehr möglich, als ursprünglich geplant war. Allerdings müssen wir auch<br />

Grenzen setzen, da man theoretisch fast unbegrenzt viele Features einbauen könnte.<br />

Man wird z.B. Materialien, Actions und Positionen von Entities direkt im Spiel ändern können.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Kehren wir wieder zu Eurem Spiel-Projekt zurück. Wie weit seid Ihr damit fortgeschritten?<br />

Martin:<br />

Das ist schwer zu sagen, weil mir immer wieder was neues einfällt. Ich denke, dass ich mit dem<br />

Level und den Grafiken zu 90% fertig bin und skript-technisch hinkt Trip leider noch hinterher.<br />

Daher würde ich das auf maximal 40% einstufen.<br />

Timo:<br />

Tatsächlich hinke ich skript-technisch noch etwas hinterher, was größtenteils daran liegt, dass ich<br />

parallel am Material Editor arbeite, um Martin eine möglichst mächtiges Tool zum Map optimieren<br />

geben zu können. Allerdings werde ich mich nun mehr auf das Spiel Konzentrieren.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Habt Ihr schon Charakter-Modelle für die Spieler und Gegner?<br />

Martin:<br />

Nein, leider noch nicht.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Was könnt Ihr aus Eurer Erfahrung zur A6-Engine sagen? Wie gut passt sie zu Eurem Projekt?<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │78


Martin:<br />

Die A6 Engine ist ausreichend für das Projekt. Allerdings hatte ich vor einiger Zeit massive<br />

Probleme, was die Lightmap-Grenze anbelangte. Leider ist die Shader-Unterstützung nicht so, wie<br />

man es sich wünscht. Insgesamt gesehen bewege ich mich am Limit der Engine. Mit verschiedenen<br />

Tricks lassen sich aber immer noch irgendwo einige FPS heraus kitzeln.<br />

Timo:<br />

Wie Martin schon gesagt hat, gehen wir mit unserem Projekt sehr an die Grenzen der A6-Engine.<br />

Aber das ist ja auch unser Ziel: Ein <strong>3D</strong> Gamestudio Projekt erschaffen, das das volle Potenzial der<br />

Engine zeigt.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Wie lange arbeitet Ihr schon an dem Projekt?<br />

Martin:<br />

Seit bestimmt 3 Jahren. Allerdings habe ich lange Pausen dazwischen eingelegt und schon fertige<br />

Dinge durch neue bessere ersetzt.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Woher bekommt Ihr Eure guten Texturen?<br />

Martin:<br />

Die erstelle ich alle selbst mit Photoshop und meiner Digicam.<br />

Einige Grundstrukturen habe ich von Noctua-Graphics.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Martin, Welche Software-Tools nutzt Du, welche Tipps kannst Du den Lesern geben?<br />

Martin:<br />

Ich benutze 3dsmax und Photoshop.<br />

Bei 3dsmax hat es sich bewährt die dort erstellten Modelle über 3ds zu exportieren und im MED zu<br />

importieren. Damit kann man sogar komplex texturierte Objekte verlustfrei in die A6 Engine<br />

bekommen.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Martin, ich habe gehört, Du arbeitest an einer für die Leser vielleicht sehr interessanten Webseite.<br />

Kannst Du uns dazu einiges sagen?<br />

Martin:<br />

Ich versuche eine Shader-Bibliothek aufzubauen.<br />

Möglichst viele A6 Shader sollen mit umfangreichen Erläuterungen und Beispielen dort verfügbar<br />

sein.<br />

<strong>3D</strong>GS-<strong>Magazin</strong>:<br />

Vielen Dank für das nette Gespräch.<br />

Das Interview wurde im Auftrag des <strong>3D</strong>GS-<strong>Magazin</strong>s von Frank Geppert durchgeführt.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │79


Game-Edit<br />

Ein Preview des Map-Editors<br />

Hallo,<br />

Im folgendem werde Ich Ihnen, den sich im Moment in Entwicklung befindenden, Map-Editor<br />

Game-Edit vorstellen.<br />

Die Idee hinter Game-Edit<br />

Die grundsätzliche Idee hinter dem Tool Game-Edit ist einfach: Der User implementiert das Tool<br />

mit 2-3 simplen Befehle in sein Projekt und kann ab nun über einen einfachen Knopfdruck den<br />

Map-Editor öffnen, in dem das Level und vorhandene Materials bearbeitet werden können. Die<br />

Änderungen sind alle Ingame sichtbar (z.B. das verschieben eines Entities um eine bestimmte<br />

Quantanzahl).<br />

Das alleine wäre noch nicht sonderlich spannend wenn Game-Edit nicht alle veränderten Daten<br />

direkt in der Map-/Wdl Datei speichern würde. Falls nötig wird sogar am Ende des Spiels gebuildet.<br />

Auf Deutsch heißt das, dass alle Änderungen die Sie in Game-Edit vornehmen auch über einen<br />

Neustart hinweg gespeichert bleiben.<br />

Anwendungsbeispiele<br />

„Das ist ja schön und gut nur wozu brauche ich das, ich habe doch WED“ werden Sie sich vielleicht<br />

fragen. Daher werde ich Ihnen nun ein Anwendungsbeispiel zeigen.<br />

Feature List<br />

• Sie starten Ihr Projekt (im folgenden Beispiel einen Ego-Shooter) und spielen es ganz<br />

normal. Beim kämpfen durch Ihr Level fällt Ihnen auf, dass der Spieler an einer bestimmten<br />

Stelle dringend noch eine Waffe/Ammopack/Lebenspack bräuchte. Deshalb öffnen Sie<br />

innerhalb des Spiels über einen Tastendruck den Map-Editor und platzieren ein neues<br />

Ammopack (u.ä.) im Level. Nun verlassen Sie Game-Edit gleich wieder und können ganz<br />

normal – mit dem neuen Ammopack weiterspielen. Dadurch ist es gut möglich, ein gutes<br />

Fine-Balancing zu erschaffen.<br />

• Grundsätzlich ähneln sich alle Anwendungsbeispiele sehr (bestimmte Einstellungen werden<br />

eben verändert), daher werde ich hier auf weitere verzichten.<br />

Schon eingebaut:<br />

• Echtzeit-Bearbeiten der Einstellungen von Modellen / Sprites und Terrains<br />

• Echtzeit-Bearbeiten der Einstellung von Materials. Unter anderem ist es auch möglich<br />

Shader Code usw. zu bearbeiten.<br />

• Ein automatischer Material Loader, der Ihren Code nach Material Definitionen durchsucht<br />

und falls nötig überschreibt.<br />

• Erschaffen, Entfernen und Morphen von Materials und Entities<br />

• Verändern der Map-Properties (Nebel u. Ambientfarben, Clipping Einstellungen)<br />

• Eine Objektliste, die alle Objekte die in der Map vorhanden sind anzeigt. Dadurch ist es<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │80


möglich mehrere Entities auf einmal zu verändern.<br />

• Eine einfach gehaltenes GUI.<br />

Geplant:<br />

Screenshots<br />

• Echtzeit-Deformierung von Terrains und Modellen<br />

• Echtzeit-Zeichnen auf Skins von Modellen und Terrains.<br />

• Ein umfangreiches Statistikfenster mit Graphen u.v.m.<br />

• Mehrfach-Entitie Erschaffung, zum erstellen von mehreren Entities auf einmal (Wälder usw.)<br />

In diesem Kapitel gibt es noch einige Screenshots des Editors. Zu beachten ist, dass dies alles work<br />

in progress (wip) Features sind. D.h. das der Editor noch in einer frühen Phase der Entwicklung ist<br />

und sich daher noch einiges ändern und vermutlich auch verbessern wird.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │81


<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │82


<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │83


Daten und Fakten<br />

Programmierer: Timo Stark aka TripleX<br />

2D Designer: Martin Teichmann aka SFMAT4<br />

633 KB und 16422 Zeilen Code<br />

2 Monate Entwicklungszeit<br />

Geschätzt, weitere 2 Monate Entwicklungszeit nötig.<br />

Einbindung in Ihr Projekt<br />

Das einbinden von Game-Edit in Ihr entsprechendes Projekt wird sehr einfach vonstatten gehen. Es<br />

ist auch für absolute Nicht-programmierer schaffbar.<br />

Ein Beispiel der Einbindung:<br />

material_init("Maps"); //Alle Map Daten liegen in dem Unterordner "Maps"<br />

Material_Bind_WDL("Data\\Scripts\\materials.wdl"); //Teilt der Engine mit, dass in der<br />

Materials.wdl Materialien liegen<br />

Material_Bind_WDL("main_op.wdl"); //Teilt der Engine mit, dass in der Main_op.wdl Materialen<br />

liegen<br />

//bis zu 40 WDL Dateien sind so einbindbar!<br />

Ich hoffe dass diese Preview Ihnen einen Einblick in Game-Edit gewährt hat.<br />

<strong>3D</strong> <strong>GAMESTUDIO</strong>-<strong>Magazin</strong> ■ <strong>Ausgabe</strong> <strong>01</strong> | <strong>Oktober</strong> 2005 │84

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!