3D GAMESTUDIO-Magazin Ausgabe 05 | Juni 2007 1
Transcription
3D GAMESTUDIO-Magazin Ausgabe 05 | Juni 2007 1
3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │1 3D Gamestudio und MySQL von Wicht Hallo und herzlich willkommen zu meinem ersten Tutorial. In diesem werdet Ihr lernen, wie man mit einer 3dgs-Anwendung Daten an einen MySQL-Server senden kann. Und auch empfangen. Und wozu? Nun, überall da, wo jeder, der Euer Spiel benutzt, auf zentral gelagerte Daten (auch von anderen Benutzern) zugreifen kann. Eine Möglichkeit wäre z.B. ein Online-Highscore-System. Ein Nutzer sendet seine erreichte Punktezahl an eine MySQL-Datenbank und sieht sofort, welche Punkte die anderen Spieler erreicht haben. Oder wie wäre es mit einem rundenbasierten Spiel? Oder einem Chat? Oder oder oder ... Möglichkeiten gibt's genug. Was brauchen wir? Zunächst einmal das 3D Gamestudio. Soweit ich weiß, können alle 3DGS-Editionen DLLs ansprechen. Ist doch prima, oder? Und dann natürlich die gshttp.dll von Peacekeeper (zu finden unter http://www.peacekeeper.com/3dgs). Und die ist auch noch kostenlos. Was will man mehr. Ach ja, ein funktionierender MySQL-Server wäre auch nicht schlecht ;-) Achtung: Ich hatte Probleme, die Anweisung HTTP_POST zu verwenden. Stattdessen verwendete ich die HTTP_GET Anweisung. Außerdem müssen Sonderzeichen wie Leerzeichen, Ü,Ä,Ö usw. noch umgewandelt werden. Aus diesem Grund habe ich die DLL um eine weitere Funktion ergänzt, die genau das macht. Die modifizierte DLL (gshttp.dll) kann unter http://www.darkware.de/3dgsmysql_tut/gshttp.dll runtergeladen werden. Wer sich zunächst einmal die ganze Materie anschauen will, ohne gleich ein Webhosting-Paket zu ordern, kann sich auch die Kombination Apache->PHP->MySQL lokal installieren. Damit kann man alles offline testen. Wie diese Programme/Module installiert werden, steht in zahlreichen Anleitungen im Internet. Wer jetzt genau aufgepasst hat, dürfte sich folgendes fragen: Nanu? Wozu auch noch den ApacheWebserver und PHP? Ich dachte immer, man kann einen MySQL-Server auch direkt ansprechen. Ihr habt recht. Natürlich geht das. Nur die meisten Webhoster wollen das aus sicherheitsrelevanten Gründen nicht und sperren den direkten externen Zugriff auf den MySQL-Server. Um aber dennoch unser Ziel zu erreichen, müssen wir PHP verwenden. Ein erster Test Jetzt wollen wir aber endlich mal was auf dem Bildschirm sehen. Erstellt eine neue 3dgs-Anwendung (nach Möglichkeit ohne die Templates zu benutzen) und kopiert die gshttp.dll in Euer Projektverzeichnis. Jetzt brauchen wir noch eine php-Datei. Die könnte etwa so aussehen: Die Datei mit dem Namen "textausgabe.php" ( den Namen könnt Ihr natürlich selbst wählen ) liegt jetzt auf meinem Webserver und kann bereits über einen Browser abgerufen werden. Bei mir sieht die URL so aus: "http://www.darkware.de/3dgsmysql_tut/textausgabe.php". Und was 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │2 macht die php-Datei? Nun, sie gibt nur einen einfachen Text aus. Mehr nicht. Im Hauptskript unserer 3dgs-Anwendung erstellen wir zunächst unser Grundgerüst. Die Zeilen 13-24 sollten eigentlich klar sein. Interessant sind allerdings die Zeilen 4-9. Über die "dllfunction"-Anweisung wird der A6-Engine mitgeteilt, welche weiteren Funktionen ihr durch eine DLL zusätzlich zur Verfügung gestellt werden. In unserem Beispiel sind es ein Teil der Funktionen, die in der Datei gshttp.dll stehen. Und nun erweitern wir unsere main-Funktion um diese neuen Befehle. Und das kommt dabei heraus: Jetzt haben wir's schon geschafft. Unsere Anwendung greift auf eine php-Datei zu, die irgendwo im 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │3 Internet erreichbar ist und liefert deren Ergebnis zurück. Die neuen Anweisungen im Überblick: HTTP_CREATE erstellt einen neuen HTTP-Client mit einer ID-Nummer. Es können also entsprechend mehrere Clients gleichzeitig erstellt werden. Sicherheitshalber sollte man sich aber mit nur einem begnügen. HTTP_GET ruft schließlich unter der gleichen ID wie HTTP_CREATE eine Datei auf dem Webserver auf. In unserem Beispiel "http://www.darkware.de/3dgsmysql_tut/textausgabe.php". HTTP_IsWorking ist ganz wichtig. Diese Funktion überprüft, ob der Webserver mittlerweile mit seiner Arbeit fertig ist. Sollte dem nicht so sein, müssen wir eben noch etwas warten. Wer will schon mit Daten arbeiten, die noch nicht da sind ;-) HTTP_RESULTS beinhaltet schließlich das Ergebnis unserer Webserver-Anfrage. In diesem Beispiel den String "Der Gargamel mag keinen einzigen Schlumpf !!!". HTTP_FREE beendet wieder den HTTP-Client. Wichtig ist, dass bei all diesen Anweisungen immer die gleiche ID-Nummer vergeben wird. In diesem Fall ist das immer 0. Grundlegend war's das schon. Spielt etwas damit, um ein Gefühl für die neuen Befehle zu bekommen. Und der MySQL-Zugriff? Nun, diejenigen die sich mit php auskennen, dürften an dieser Stelle schon jubeln. Allen anderen sei gesagt, dass der reine MySQL-Zugriff über php realisiert wird. Und das schauen wir uns jetzt mal an. Wir legen uns erstmal eine Tabelle via phpMyAdmin an. Ein Datenbank-Tutorial liegt mir zwar fern, dennoch möchte ich auf einige wenige, aber wichtige, Dinge eingehen. Das erste Feld sollte immer eine laufende Nummer UND ein Primärschlüssel sein. Dadurch hat man die Möglichkeit, auch inhaltlich gleiche Datensätze zu unterscheiden. In diesem Screenshot könnt Ihr sehen, das das erste Feld vom Typ "int" (Ganzzahl) in der Spalte "Extra" ein "auto-increment" besitzt. Das heißt nichts weiter, als das bei jedem neuen Datensatz die Nummer des Feldes um den Wert 1 erhöht wird. Der untere Screenshot verdeutlicht das. Das Feld "3dgsmysql_tut_nr" ist genau dieses Feld mit dem Primärschlüssel und dem Extra "autoincrement". Hinweis: phpMyAdmin ist eine in der Skriptsprache PHP geschriebene Webseite, mit deren Hilfe MySQL-Datenbanken recht komfortabel verwaltet werden können. Kostenloser Download unter http://www.phpmyadmin.net. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │4 OK, wir haben also unsere Tabelle, mit mehr oder weniger sinnvollem Inhalt, angelegt. Als nächstes erstellen wir eine neue php-Datei, welche den gesamten Inhalt der Tabelle ausliest. Zunächst brauchen wir aber eine php-Datei, welche die Zugangsdaten enthält. Sie heißt "global.php". Und dann noch die php-Datei, die den Datenbankinhalt ausliest. Das obige Bild zeigt den Inhalt der Datei "textausgabe_db.php". Die Datei "textausgabe_db.php" bindet die Datei "global.php" mit Hilfe des include-Befehls ein. Also ganz analog dem include-Befehl in C-Script. Man könnte also auch die Datei "global.php" weglassen und die Zugangsdaten direkt in die Datei "textausgabe_db.php" eintragen. Mit ständig ansteigender Anzahl an php-Dateien wird man jedoch die Auslagerung der Zugangsdaten in eine separate Datei zu schätzen wissen. In den Zeilen 7-10 wird eine Datenbankverbindung aufgebaut und eine SQL-Anweisung gesendet. Die Zeile 12 hätten wir sogar weglassen können. In der Zeile 13 wird ermittelt, wieviele Datensätze als Ergebnis der Abfrage zurückgeliefert wurden. Dieser Wert wird benötigt, damit wir eine Schleife ausführen können (Zeile 15-21), um jeden einzelnen Datensatz mithilfe der echo-Anweisung auszugeben (Zeile19). Die Zeile 20 ist nur dazu da, einen Zeilenvorschub zu integrieren. Die php-Anweisung mysql_result in den Zeilen 16 und 17 liest die einzelnen Werte des aktuellen Datensatzes aus. Der erste Parameter ($res) beinhaltet das gesamte Abfrageergebnis. $i definiert den aktuellen Datensatz in der for-Schleife. Der dritte und letzte Parameter definiert des Feld. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │5 Schaut Euch dazu nochmal den unteren Screenshot an. Wenn der dritte Parameter 0 ist, dann meinen wir damit das erste Feld. Also "3dgsmysql_tut_nr". Bei einer 1 entsprechend das Feld "dw_3dgsmysql_tut_text", usw. ... In unserer C-Skipt-Datei ändert sich allerdings nicht viel. Wir haben ein weiteres Textelement, welches den Inhalt unserer "textausgabe_db.php" darstellt. HTTP_CREATE, HTTP_GET usw. sollten an dieser Stelle auch keine weiteren Fragen aufwerfen. Und hier ist das Ergebnis ... Mehr gibt's eigentlich zum empfangen von MySQL-Daten nicht zu sagen. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │6 Senden von Daten an einen MySQL-Server Auch an dieser Stelle dürften Anwender, die mit php Erfahrung haben, jubeln. Um Daten an einen MySQL-Server über eine php-Datei zu senden, werden diese einfach an das Ende der URL angehängt. Das sieht dann z.B. so aus: "http://www.darkware.de/3dgsmysql_tut/neuerdatensatz.php?user=Wicht&text=lustig". Der php-Datei "neuerdatensatz.php" werden die Variable "user" mit dem Inhalt "Wicht" und die Variable "text" mit dem Inhalt "lustig" übergeben. Und mit diesen Variablen ( und deren Werten ) kann man in PHP weiterarbeiten. Wir werden unsere kleine 3dgs-Anwendung so erweitern, dass gleich 2 Werte an einen MySQLServer übertragen werden. Dazu habe ich zunächst die Tabelle um ein weiteres Feld erweitert. Wie Ihr sehen könnt, wurde mit phpMyAdmin ein neues Feld "username" zwischen den beiden schon vorhandenen Feldern eingefügt ( Typ: varchar; Länge 60 ). Die Datei "neuerdatensatz.php, welche Daten an den MySQL-Server sendet, sieht so aus: Zeile 3: Den include-Befehl kennen wir bereits. Zeile 5: Hier wird die Variable "user" abgefangen, die wir in unserer URL angegeben haben Zeile 6: Wie Zeile 5, nur mit der Variablen "text". Hinweis: Einige von Euch werden jetzt bestimmt anmerken, dass man die Variablen und deren Werte auch mit der globalen Variable $QUERY_STRING abfragen kann. Das ist auch soweit richtig. Nur haben auch da einige Webhoster ihre eigenen Vorstellungen. Der Webhoster Strato, bei dem ich bin, "mag" diese Variable nicht. Stattdessen soll man $_GET verwenden. Die Zeilen 10-13 sollten soweit klar sein. Es wird eine Verbindung aufgebaut und die Daten werden über eine SQL-Anweisung abgeschickt. Da wir jetzt aber ein weiteres Feld in der Datenbanktabelle haben, müssen wir auch unsere "textausgabe_db.php" etwas modifizieren. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │7 Viel geändert haben wir da nicht. Interessant sind aber die Zeilen 21,23 und 24. Die Angabe "\n" steht hier für einen Zeilenvorschub. Was der genau bewirkt, seht Ihr dann, wenn Eure 3dgsAnwendung gestartet wurde. Logischerweise müssen wir auch in der C-Skript-Datei etwas ändern. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │8 OK, gehen wir die wdl-Datei Schritt-für-Schritt durch. Zeile 04: Eine weitere Funktion wurde eingefügt. Was diese bewirkt, werden wir gleich noch sehen. Zeile 15: Ein String zum temporären abspeichern eines neuen Users. Zeile 16: Ein String zum temporären abspeichern eines neuen Textes. Zeile 17: In dieser Variable steht dann die komplette URL inkl. Datenanhang Zeile 40: Wir müssen den String in eine url-konforme Zeichenkette umwandeln ( z.B. wird aus einem Leerzeichen ein %20; aus einem ü wird ein %FC usw. ) Zeile 41: Gleiches gilt auch für diese Variable. Die komplette URL sieht ohne die entsprechende Umwandlung ab Zeile 48 so aus: http://www.darkware.de/3dgsmysql_tut/neuerdatensatz.php?user=Wicht&text=Schlümpfe anschauen macht Spaß Mit Umwandlung so: http://www.darkware.de/3dgsmysql_tut/neuerdatensatz.php?user=Wicht&text=Schl%FCmpfe%20 anschauen%20macht%20Spa%DF Ihr könnt das auch gerne überprüfen, indem Ihr die nicht umgewandelte URL in Euren Browser eintippt. Der Browser wandelt diese Zeile ebenfalls um. Der Rest der wdl-Datei dürfte mittlerweile verständlich sein. Mit HTTP_CREATE wird ein neuer Http-Client erzeugt. HTTP_GET ruft die URL auf. Dann warten wir, bis der Webserver alles erledigt hat (HTTP_IsWorking). Zum Schluss wird noch der HTTP-Client freigegeben. Die C-Skript-Zeilen zum abrufen von Daten haben sich derweil nicht verändert. Nach dem Start unserer 3dgs-Anwendung sehen wir dieses Bild ... Ein kontrollierender Blick via phpMyAdmin zeigt uns, dass die neuen Daten tatsächlich vorliegen ... Das war's dann auch erstmal. Ich hoffe, Euch mit diesem Tutorial halbwegs geholfen zu haben. Fehler, Anregungen, Kritiken usw. könnt Ihr gerne an info@darkware.de. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │9 Terrainerstellung mit Earthsculptor Dieses Tutorial beschäftigt sich mit der Terrainerstellung Earthsculptor [1] und dem Import in 3D Gamestudio. mittels dem kostenlosen Tool Wichtig ist hierbei allerdings noch, dass dieses Verfahren nur ab der Commercial Version funktioniert, da nur ab der Com Shader möglich sind. Nachdem man Earthsculptor heruntergeladen, installiert und gestartet hat, klickt man auf File -> New. Wir belassen es für den Moment bei den Standardeinstellungen. Nun sehen wir also folgendes Bild (ich habe das kleine Fenster maximiert): Wen der Nebel stört, der klickt im rechten Fenster auf „Fog" und schiebt dann den Regler „Far" nach ganz rechts. Nun haben wir also ein sehr klares Bild. In der Toolbox klicken wir nun auf den Button „Detail" (Das Karomuster). Das Fenster auf der rechten Seite sieht nun so aus: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │10 In der oberen Reihe sehen wir 4 Buttons, die wir jeweils mit einer Textur belegen können. D.h. also, dass wir für unser Terrain bis zu 4 unterschiedliche Texturen verwenden können. Dabei gilt folgende Regel: Eine Textur überlagert immer alle Texturen auf den Buttons links von ihr. D.h. Nr. 4 überlagert alles, Nr. 1 Nichts. Klicken wir nun auf „Set Detail Texture" und wählen beispielsweise „longGrass.png" als Textur aus. Das Terrain verändert sich sofort zu folgendem Bild: Nun machen wir am besten damit weiter das Terrain ein wenig zu verformen. Dazu klicken wir in der Toolbox auf das Symbol oben rechts „Terraform". Das Fenster auf der rechten Seite sieht nun so aus: Einfaches experimentieren mit den verschiedenen Tools ergibt meist schon recht schöne Ergebnisse. Hierzu gebe ich keine genauere Anleitung, da sich die meisten Dinge beim experimentieren erschließen. Die 3 Regler unter den Buttons geben den Radius des Tools, die Stärke der Veränderung und die Stärke des Randes an. Hier mal mein Beispiel Terrain nachdem ich einfach ein wenig mit den Tools herumgespielt habe: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │11 Nun klicken wir in der Toolbox wieder auf „Detail". Wählen bei den 4 Buttons die Nr. 2 aus und klicken auf „Set Detail Texture". Hier habe ich nun „cliff.png" gewählt, da ich nun die Berge bemalen wollte. Nachdem die Textur ausgewählt ist können wir nun mit dem Bemalen des Terrains beginnen. Die Regler sind ähnlich aufgebaut wie beim Verformen des Terrains. Ein kurzes Zwischenergebnis: Nun habe ich weitergemacht und auf die selbe Art und Weise die Detail-Textur 3 und 4 belegt und auf das Terrain gemalt: Klicken wir nun einmal auf den Pinsel „Paint" in der Toolbox. Nun können wir im Farbauswahlfenster links eine Farbe wählen und auf das Terrain mahlen. Ich habe grün gewählt und auf das Gras gemalt. Dadurch wirkt es saftiger und frischer: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │12 Dies stellt nun auch das Endergebnis dar. Das Wasser ist hier nur ein Gimmick und kann nicht mit exportiert werden. Klicken wir also nun auf File -> Save und speichern unser Terrain in einen beliebigen (am besten leeren) Ordner ab. In diesem Ordner haben wir nun 5 Dateien: „tutterrain.map" ist die Earthsculptor-Datei „tutterrain.png" ist die Heightmap aus der MED gleich das Terrain generieren wird „tutterrain_c0.png" ist die Colormap. Hier ist das saftige Grün unseres Grases gespeichert „tutterrrain_d0.png" ist eine RGB-Blendmap. Diese Information dient dem Shader dazu die 4 Texturen richtig zu mischen. „tutterrain_I0.png" ist die Shadowmap. Hier ist also die Beleuchtung gespeichert. Nun müssen wir zuerst die Dateien umwandeln in andere Formate, damit MED damit etwas anfangen kann. Das könnte etwas kompliziert werden, da man hier einige Umwege gehen muss. Fangen wir mit der Datei „tutterrain.png" an. Diese wandeln wir am besten in eine .tga oder eine .pcx Datei um .bmp würde zwar auch gehen, aber MED interpretiert diese bei mir nicht. Daher wählen wir am besten TGS oder PCX. Das geht am einfachsten mit einem Tool wie dem EasyGraphicsConverter [2]. Nun kommen wir zur Colormap, also die mit der Endung „_c0.png". Diese öffnen wir zuerst mit Windows Paint und speichern sie als BMP Datei ab. Wie bereits erwähnt hat MED Probleme mit den BMP Dateien und deswegen wandeln wir sie gleich mit dem EasyGraphicsConverter [2] in eine PCX Datei um. Mit der Blendmap „_d0.png" verfahren wir genauso. Also zuerst Paint -> Speichern als BMP -> Umwandeln in eine PCX Datei. Die Shadowmap „_I0.png" öffnen wir zuerst mit Photoshop oder Paint und stellen den Bildmodus von Graustufe auf RGB um, sonst haben wir später Kanten bei den Schatten. Die Shadowmap speichern wir diesmal gleich als PCX Datei. WICHTIG! Die Blendmap und die Colormap nicht mit einem Programm wie Photoshop öffnen. Dann Photoshop und Co. Interpretieren die Transparenz in den beiden Dateien falsch und beim Speichern erhält man schlichtweg leere Dateien. Deswegen diese immer über Paint speichern, dann dieses stellt keine Transparenzen dar. So, nun haben wir also alle Dateien im PCX Format. Öffnen wir nun den MED. In MED klicken wir nun auf File -> Import -> Import Terrain from Pic Dort wählen dann als Dateiformat PCX aus und öffnen die „tutterrain.pcx" (also die Datei ohne Endung). Im sich nun öffnenden Fenster stellen wir 100 x 100 Vertices ein. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │13 Bei mir ließen sich über die Regler nur 99 x 99 einstellen, was aber nicht weiter schlimm ist. Nach einem Klick auf „OK" sehen wir also nun unser in Earthsculptor erstelltes Terrain. Allerdings ist es noch ein wenig zu flach. Wir klicken also auf das Skalierungstool und skalieren das Terrain ein wenig in die Höhe, bis in etwa an das in Earthsculptor herankommt. Nun öffnen wir das Skins-Menü (Edit -> Manage Skins) Nun wählen wir den „Skin0" an und klicken auf „Skin Settings" Wir machen einen Haken bei „Texture" und klicken auf „Texture File" und dann auf „...". Hier wählen wir die Colormap aus. Also als Dateiformat PCX und dann die Datei mit der Endung „_c0.pcx". Dann klicken wir auf „New Skin" machen wieder einen Haken bei „Texture" und wählen diesmal die RGBBlendmap aus („_d0.pcx"). Und das ganze wiederholen wir noch ein drittes Mal und wählen als letztes die Shadowmap („_I0.pcx") als Textur aus. Das war's um Großen und Ganzen im MED schon. Wir speichern nun nur noch das Terrain als HMP ab. Wechseln wir nun zum WED. Nach einem Klick auf „New" wählen wir über Object -> Load Entity als Dateiformat HMP aus und öffnen unser Terrain. Dann speichern wir den Level ab und klicken dann auf File -> Map Properties. Hier klicken wir bei Script auf das Blatt Papier und wählen dann „template" aus. Jetzt können wir WED erstmal wieder schließen und öffnen die .WDL Datei, die nun in unserem 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │14 Ordner liegt. Wir bearbeiten sie so, dass sie wie folgt aussieht: Bei „path" solltet ihr den Pfad zu eurem Projektordner angeben. Die Datei „terrain_multitex.wdl" [3] kopiert ihr in euren Projektordner. Nun müssen wir noch einmal ein bisschen mit Dateiformaten und Bildern jonglieren. Dazu müssen wir zuerst einmal in Earthsculptor bei „Detail" mit der Maus über die Buttons gehen um die Dateinamen der Texturen herauszufinden. Nun müsst ihr diese Dateien (zu finden im Earthsculptor Ordner unter Textures) mit einem Konvertierungsprogramm in das PCX oder BMP Format konvertieren. Desweiteren müsst ihr darauf achten, ob die Texturen eine Größe von 256x256, 512x512 oder 1024x1024 haben. Wenn nicht, müsst ihr sie noch skalieren, ansonsten gibt es nachher unschöne schwarze Ränder auf dem Terrain. Die konvertieren Dateien legen wir ebenfalls in unseren Projektordner. Nun öffnen wir die Datei „terrain_multitex.wdl" und gehen in die Zeilen 32 – 35. Hier sind die Texturen angegeben, die nachher auf dem Terrain verwendet werden. Wir müssem hier die Texturnamen von den eben konvertierten Texturen angeben. Dabei ist Button 1 in Earthsculptor „tex3" und Button 4 „tex6". Nun haben wir es fast geschafft. Nachdem wir die Datei abgespeichert haben, öffnen wir in WED wieder unseren Level mit dem Terrain. Wir wählen es an und wählen mit einem Rechtsklick „Properties" klicken auf das Behaviour Reiter und klicken dann auf das Ordner-Symbol. Hier wählen wir dann Aktion „multi_rgb". Nun kompilieren wir den Level und bewundern unser Endergebnis: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │15 Ich hoffe, dass ich hiermit einen Einblick sowohl in Earthsculptor als auch in das Importieren in 3D Gamestudio geben konnte. Sollte ihr Fragen haben, könnt ihr die gerne im Forum oder im Gästebuch meiner Webseite loswerden. Ein Dank geht an Loopix, der den Shader für das Terrain zur Verfügung gestellt hat als auch an Nagashi, der den Shader für die Colormap modifiziert hat. DANKE! die Downloadlinks: [1] Earthsculptor [2] EasyGraphicsConverter [3] Terrain_multitex Shader [4] Beispielprojekt 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │16 Die Sache mit der Motivation Wenn ein Mann etwas ganz blödsinniges tut, so tut er es immer aus den edelsten Motiven(Oskar Wilde) Es wurde schon viel über Projektmanagement, Teamarbeit und Planung geschrieben. All dies bringt nicht viel, wenn keine oder kaum Motivation vorhanden ist, das geplante Projekt umzusetzen. In diesem Artikel soll es nun um die Mannigfaltigkeit der Motivation gehen. Hierbei muß klar sein: Nicht alles wirkt bei jedem. Aber es wird jeder in der Lage sein, aus diesem Artikel etwas nützliches für sich herauszulesen. Ich werde diesen Artikel ausnahmsweise und entgegen unserer Konventionen in der „Du" Form schreiben, da es ein recht persönliches Thema ist. Ich denke, so kommen wir am ehesten weiter. Vielleicht sollten wir erstmal beleuchten, was genau überhaupt Motivation ist. Wie entsteht der starke Drang von innen heraus, Energie in eine bestimmte Sache zu stecken, die nicht extentiell wichtig ist? Du mußt hier zwischen der inneren und der äußeren Motivation entscheiden. Innere Motivation ist schwieriger zu erzeugen, aber nachhaltiger. Äußere Motivation ist schnell „erheischt", aber verpufft auch ebenso schnell wieder. Ganz so einfach ist es natürlich nicht jedem Psychologen würden die Haare zu Berge stehen. Beide sind eng miteinander verknüpft und beeinflussen sich. Du wirst sehen, nur die Mischung macht´s. Motivation kommt von „Motiv" - ohne ein solches keine Motivation. Du kannst also nichts erzwingen. Die gute Nachricht: Das brauchst und sollst Du auch gar nicht! Die von uns allen gewünschte, innere Motivation braucht also einen Auslöser. Es können auch mehrere sein, wichtig ist nur, daß dieser Auslöser eine Perspektive gibt, an die Du glauben kannst. Hier entscheidet wiederum die eigene Skepsis und Begeisterungsfähigkeit. Motivation ist aber gleichzeitig keine auf ein Projekt bezogene Gefühlsregung. Vielmehr ist Motivation etwas allgemeines. Wenn Du in der Schule motiviert bist, trifft das auch auf viele andere Bereiche des Lebens zu. Es gilt also, sich ein entsprechendes, „motivierendes" Umfeld zu schaffen. Hier kann hoffentlich jeder auf einen gewissen Erfahrungsschatz zurückblicken. Gleichzeitig, bei ersten Erfolgserlebnissen, fährt die Skepsis zurück - neue Horizonte tun sich auf. Es gibt einige Patentrezepte, um die Motivation zu erhöhen. Du solltest Dir diejenigen raussuchen, die den größten Erfolg versprechen. Termin setzen Wenn eine Sache drängt und sie Dir wichtig ist, solltest Du Dir einen festen Termin dafür setzen. Dieser Artikel ist so entstanden. Wenn Du diesen Termin öffentlich machst, erhöht sich der Druck. Termine dürfen nicht utopisch früh gewählt sein. Langes Überziehen des Termins bis zur Erfüllung bewirken nämlich genau das Gegenteil - Demotivation. Darum solltest Du vorsichtig mit dieser Methode umgehen. Belohnungen Belohnungen müssen gar nicht mal vorgesehen sein. Oftmals entstehen sie von alleine. Die vielen Leser des Magazins sind mir z.B. Lohn genug. Allerdings kann es helfen, sich nach getaner Arbeit etwas zu gönnen. Kleine Ziele setzen Auch dies ist eine Gratwanderung. Kleine Ziele dürfen nicht unbedeutend sein, sonst verkehrt sich der Motivationseffekt ins Gegenteil. Kleine, aber ambitionierte Ziele helfen, eine große Sache überschaubar zu machen. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │17 Bei Projektarbeit: Spielen! Wenn Du mal wieder gar keine Lust hast, an einem Spiel weiterzumachen, so spiele es eine Weile. Meist wird Dir dann bewußt, wie viel Arbeit schon drin steckt. Und es gehört schon eine ordentliche Portion Melancholie dazu, dann nicht weiterzumachen. Auch hier gibt es zwei Seiten der Medaille: Vielleicht fallen Dir lauter Baustellen auf, die Dich in diesem Moment überfordern. Du sagst Dir: Wie soll ich das alles nur schaffen? Nun, bevor Du mit falschem Stolz und überzogenen Erwartungen nicht weitermachst, schmeiße lieber einige Features raus. Du wirst sehen, wie der Druck von Dir weicht. Das ist kein Grund, wieder unmotiviert zu werden. Im Gegenteil: Du beweißt gesunden Menschenverstand, indem Du alte Meinungen und Vorurteile revidierst! Vor drei Jahren warst Du vielleicht der Meinung, es muß ein MMORPG werden. Es ist nicht schlimm, wenn es doch nur ein normales RPG wird. Kommunikation Viele User im Forum reden gerne - sei es über Chat, Mails oder PM. Tausche Dich mit ihnen aus. Nimm das Zusammengehörigkeitsgefühl auf, sauge es ein! Sich gegenseitig zu motivieren ist zwar nicht so nachhaltig wie die Eigenmotivation - aber es hängt zusammen. Durch konstruktive Gespräche steigt Deine Laune ebenso wie Deine innere Motivation. Und zwar unterbewußt. Motiviere Dich bewußt Das ist vielleicht etwas hölzern ausgedrückt, darum gebe ich Dir ein Beispiel: Wenn Dir jemand ein Kompliment macht - nimm es an. Sag´"Danke! Das ist nett von Dir!". Das hat viele positive Effekte. Dein Selbstbewußtsein wird aufgebaut und Dein Gegenüber freut sich. Viel mehr, als wenn Du in falscher Bescheidenheit sagst: „Na ja, so toll ist es auch nicht..." Setz´ Dich nicht unter Druck Wenn Du gar keine Lust hast, solltest Du keinen Termin setzen oder mit dem Kopf durch die Wand wollen. Das ist okay und kein Grund zu verzweifeln. Motivation kann man nicht erzwingen. Man kann sie sich nur „erfühlen". Umgebe Dich nicht mit Schwarzsehern. Sei Dir immer sicher, das alles klappt - dann gibt es keine Gründe mehr verzweifelt zu sein. Du kannst es, Du machst es und Du weißt es. Wo ist das Problem? Leg´ die Beine hoch, Du schaffst es doch sowieso! Lass Dich nicht runterziehen Wenn Du im Team arbeitest, dann steht und fällt die Motivation. Das ist ganz natürlich und kein Prozess, den man so einfach aufhalten kann. Stattdessen solltest Du mit gutem Beispiel voran gehen und signalisieren, daß Du an den Erfolg des Teams glaubst. In guten wie in schlechten Zeiten. Wenn Du als Konstante fungierst, werden andere Teammitglieder davon mitgerissen. Drohungen, Beschwerden und ähnliches helfen nicht. Das mußte ich selbst auch schon feststellen. Häng´ das Projekt nicht am Team auf. Wenn Peter das getan hätten, wäre Mausgame nicht so weit, wie es ist. Einfach anfangen! Den inneren Schweinehund zu überwinden ist nicht einfach. Ich mußte das auch tun, um diesen Artikel zu schreiben. Aber siehe da: Es macht Spaß! Ich bin völlig überrascht von mir selbst! Das kannst Du auch. Überrasche Dich immer mal wieder selbst, es ist fast so schön als wenn das andere tun. Nimm´ Dich nicht so ernst Das kannst Du Dir nicht oft genug sagen. Wenn irgendwelche Steine im Weg liegen und Du stolperst, lach drüber! Du kannst nur draus lernen und gestärkt daraus hervorgehen. Die wenigsten Stolpersteine sollte man persönlich nehmen. Betrachte sie als Herausforderung, 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │18 vielleicht sogar als leicht tragischen Gag. Das nimmt ihnen die Härte und sorgt dafür, daß Du ihnen nicht „ohnmächtig" gegenüberstehst. Ich bin mir sicher, daß dieser Artikel einiges in Dir bewirken wird. Lass es raus! Ich hätte auch schreiben können, daß ich HOFFE, daß dieser Artikel weiterhilft. Dem ist nicht so. Stattdessen bin mir einfach sicher, daß er hilft. Basta. Ein schönes Gefühl. ;-) Viel Spaß beim ausprobieren wünscht, Torsten Fock www.vulkanware.de 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │19 Einfache Physik durch Event Funktionen ohne Newton und dergleichen Ich möchte in diesem Tutorial mit Ihnen ein paar einfache Physik Bewegungen programmieren um Objekte durch Berührung oder Beschuss zu bewegen. Mann möge mir verzeihen wenn ich nicht die Befehle my.poligon = on und c_trace für poligongenaue Abtastung verwende, aber da ich nur eine Sybex Version besitze sind diese Befehle bei mir nicht möglich und ich möchte hier keine Skripte bzw. Befehle abdrucken die ich nicht getestet habe. Inhalt: 1. Vorstellung des Skriptes 2. Vorstellung der Aktion 2.1 Die Aktion "entity_1" 3. Vorstellung der Funktionen 3.1 Die Funktion "function ent_col_event1();" // Event Funktion der Entity 3.2 Die Funktion "function physik_1();" // Hauptfunktion der Entity 3.3 Die Funktion "function Max_Min_Berechnung();" // Grenzen der Bounding Box 3.4 Die Funktion "function Abstand_zum_Boden();" // Abstandsberechnung zum Boden 3.5 Die Funktion "function Abstand_Ecken();" // Abstandsberechnung der Ecken 3.6 Die Funktion "function Schieflage();" // Schieflage der Entity über Abgrund 3.7 Die Funktion "function Anziehungskraft();" // Anziehungskraftberechnung der Entity 3.8 Die Funktion "function Drift();" // Drift der Entity bei Schieflage 3.9 Die Funktion "function Kraftfaktor();" // Kraftfaktorberechnung bei Berührung 3.10 Die Funktion "function Bewegung();" // Bewegung der Entity Bestimmte Variablen und die Handle der Entities werden im Skript in Arrays abgespeichert. Sollte Ihnen die Verwendungsweise von Arrays nicht geläufig sein, können Sie in diversen Publikationen und Tutorials mehr über diese Art der Speicherung erfahren. Im 3dgsMagazin No.2 finden Sie auch ein Tutorial über die Benutzung von Arrays. Ich werde hier nicht im Einzelnen auf die Funktionsweise von Arrays eingehen da dies den Rahmen hier sprengen würde. Sämtliche Funktionen funktionieren auch mit dem Player der Template Skripte. Sie müssen nicht erst einen eigenen Player-Skript schreiben. 1. Vorstellung des Skriptes Zuerst einmal möchte ich Ihnen das Skript vorstellen. Danach werde ich im Einzelnen auf die verschiedenen Aktionen und Funktionen eingehen um Ihnen die Funktionsweise näher zu bringen. ////////////////////////////////////////// //// Definitionen für Bewegungskörper //// ////////////////////////////////////////// 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │20 define _gewicht,skill1; define _entity_x,skill2; define _entity_y,skill3; define _entity_z,skill4; define _MaxMin_x,skill8; define _MaxMin_y,skill9; define _MaxMin_z,skill10; //define _speed,skill11; // Noch nicht in Verwendung //define _speed_x,skill11; // Noch nicht in Verwendung //define _speed_y,skill12; // Noch nicht in Verwendung //define _speed_z,skill13; // Noch nicht in Verwendung define _dist_floorR,skill14; define _dist_floorL,skill15; define _dist_floorF,skill16; define _dist_floorB,skill17; define _dist_floorM,skill18; define _ABSOLDIS,skill34; define _ABSOLDIS_X,skill34; define _ABSOLDIS_Y,skill35; define _ABSOLDIS_Z,skill36; define _floornormal1,skill37; define _floornormal1_X,skill37; define _floornormal1_Y,skill38; define _floornormal1_Z,skill39; define _f_drift,skill40; define _move_x,skill41; define _move_y,skill42; define _force,skill43; define _move_force,skill44; define _Bewegung_Vert,skill45; define _Bodenhöhe,skill46; define ent_id,skill47; define entity_id,skill48; ////////////////////////////////////////////////////////// //// Variablen in Verbindung mit Templates ausblenden //// ////////////////////////////////////////////////////////// var force[3] =0,0,0; var friction; var slopefac; var gravity; /////////////////// //// Variablen //// /////////////////// var temp_1; var temp_2; var t; 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │21 var ent_nr; ///////////////////////////// //// String und Entities //// ///////////////////////////// entity* Koerper; //////////////// //// Arrays //// //////////////// var ent_array1[8000]; //////////////////// //// Funktionen //// //////////////////// function ent_col_event1(); // Event Funktion der Entity function Max_Min_Berechnung(); // Grenzen der Bounding Box function Abstand_zum_Boden(); // Abstandsberechnung zum Boden function Abstand_Ecken(); // Abstandsberechnung der Ecken der Entity zum Boden function Schieflage(); // Schieflage der Entity über Abgrund function Anziehungskraft(); // Anziehungskraftberechnung der Entity function Drift(); // Drift der Entity bei Schieflage function Kraftfaktor(); // Kraftfaktorberechnung bei Berührung der Entity function Bewegung(); // Bewegung der Entity //uses _Gewicht,_entity_x,_entity_y,_entity_z, action entity_1 { Koerper = my; t += 10; ent_nr = t; my.ent_id = ent_nr; my.fat = off; my.narrow = on; //my.passable = on; my.push = 0; if (my._gewicht == 0) {my._gewicht = 10;} my.event = ent_col_event1; my.enable_sonar = on; my.enable_shoot = on; my.enable_block = on; my.enable_entity = on; my.enable_impact = on; my.enable_push = on; my.enable_click = on; physik_1(); } 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │22 function ent_col_event1() { if(event_type == event_impact) { if(my == null){return;} if(you == null){return;} ent_nr = my.ent_id; //// Koordinaten Trefferpunkt //// ent_array1[ent_nr*10+0] = target[0]; ent_array1[ent_nr*10+1] = target[1]; ent_array1[ent_nr*10+2] = target[2]; //// Koordinaten auslösende Entity //// ent_array1[ent_nr*10+3] = you.x; ent_array1[ent_nr*10+4] = you.y; ent_array1[ent_nr*10+5] = you.z; //// Gewicht der Entity //// if(you.skill1 == 0){temp = 10;} if(player == you){temp = 10;} ent_array1[ent_nr*10+6] = temp; //// Geschwindigkeit der Entity //// if(you.skill11 == 0){you.skill11 = 10;} ent_array1[ent_nr*10+7] = you.skill11; //// Winkel Aufprallrichtung //// vec_diff(temp_1,target,you.x); //// Abprallwinkel //// vec_to_angle (temp,normal); ent_array1[ent_nr*10+8] = temp.pan; ent_array1[ent_nr*10+9] = temp.tilt; //// Schiebende Kraft //// my._force = ent_array1[ent_nr*10+6] * ent_array1[ent_nr*10+7]; } if(event_type == event_shoot) { if(my == null){return;} if(you == null){return;} ent_nr = my.ent_id; //// Koordinaten Trefferpunkt //// ent_array1[ent_nr*10+0] = target[0]; ent_array1[ent_nr*10+1] = target[1]; ent_array1[ent_nr*10+2] = target[2]; 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │23 //// Koordinaten auslösende Entity //// ent_array1[ent_nr*10+3] = you.x; ent_array1[ent_nr*10+4] = you.y; ent_array1[ent_nr*10+5] = you.z; //// Gewicht der Entity //// temp = you.skill4; if(player == you){temp = 10;} ent_array1[ent_nr*10+6] = temp; //// Geschwindigkeit der Entity //// ent_array1[ent_nr*10+7] = you.skill5/2; //// Winkel Aufprallrichtung //// vec_diff(temp_1,target,you.x); //// Abprallwinkel //// vec_to_angle (temp,normal); ent_array1[ent_nr*10+8] = temp.pan; ent_array1[ent_nr*10+9] = temp.tilt; //// Schiebende Kraft //// my._force = ent_array1[ent_nr*10+6] * ent_array1[ent_nr*10+7]; } if (event_type == event_click) // Noch nicht in Verwendung { koerper = me; } } function physik_1() { Max_Min_Berechnung(); if(my._entity_x == 0) { my._entity_x = my._MaxMin_x; } if(my._entity_y == 0) { my._entity_y = my._MaxMin_y; } if(my._entity_z == 0) { my._entity_z = my._MaxMin_z; } while(1) { Abstand_zum_Boden(); Abstand_Ecken(); 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │24 Anziehungskraft(); Schieflage(); Drift(); Kraftfaktor(); Bewegung(); wait(1); } } function Max_Min_Berechnung() { my._MaxMin_x = (my.max_x - my.min_x); my._MaxMin_y = (my.max_y - my.min_y); my._MaxMin_z = (my.max_z - my.min_z); } function Abstand_zum_Boden() { vec_set (temp,nullvector); vec_set(temp,my.x); temp.z -=4000; vec_set(temp_1,my.x); temp_1.z = my.z - ((my._entity_z)/2); trace_mode = ignore_me + ignore_sprites + ignore_models + scan_texture; my._BODENHÖHE = trace(temp_1,temp); // my._BODENHÖHE beinhaltet die Entfernung zum Boden my._floornormal1_X = NORMAL.X;// my._floornormal auf die Normale des Bodens richten my._floornormal1_Y = NORMAL.Y;// my._floornormal auf die Normale des Bodens richten my._floornormal1_Z = NORMAL.Z; } function Abstand_Ecken() { //// Trace von Mitte nach unten //// vec_set(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorM = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); //// Trace von links nach unten //// vec_set(temp.x,vector(0,(my._entity_y/2),0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my.max_z - my.min_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorL = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │25 //// Trace von rechts nach unten //// vec_set(temp.x,vector(0,-(my._entity_y/2),0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorR = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); //// Trace von vorne nach unten //// vec_set(temp.x,vector((my._entity_x/2),0,0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorF = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); //// Trace von hinten nach unten //// vec_set(temp.x,vector(-(my._entity_x/2),0,0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorB = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); } function Schieflage() { temp = abs(my._dist_floorF - my._dist_floorB); if(temp <= 1) { my.tilt = 0; my._f_drift = 0; } temp = abs(my._dist_floorL - my._dist_floorR); if(temp <= 1) { my.roll = 0; my._f_drift = 0; } if (my._dist_floorM <= 2) {return;} if (my._dist_floorM > 5 && my._dist_floorL > 5 && my._dist_floorR > 5 && my._dist_floorF > 5 && my._dist_floorB > 5) { return; } if (my._dist_floorL >= 5) { temp = atan(my._dist_floorL/(my._entity_y/2)); if(temp > abs(my.roll)) // Absolutberechnung da Roll negativ ist { 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │26 my.roll -= 1 * time; } } if (my._dist_floorR >= 5) { temp = atan(my._dist_floorR/(my._entity_y/2)); if(temp > my.roll) { my.roll += 1 * time; } } if (my._dist_floorF >= 5) { temp = atan(my._dist_floorF/(my._entity_x/2)); if(temp > abs(my.tilt)) // Absolutberechnung da Tilt negativ ist { my.tilt -= 1 * time; } } if (my._dist_floorB >= 5) { temp = atan(my._dist_floorB/(my._entity_x/2)); if(temp > my.tilt) { my.tilt += 1 * time; } } } function Anziehungskraft() { if (my._dist_floorM>5&&my._dist_floorL>5&& my._dist_floorR>5&&my._dist_floorF>5&& my._dist_floorB > 5) // in der Luft? { force.z = -5; // Schwerkraft friction = 0.1; // Luftwiederstand // Geschwindigkeit vertikal my._Bewegung_Vert = time*force.z + max(1-time*friction,0)*my._Bewegung_Vert; my._absoldis_Z = time * my._Bewegung_Vert; } if (my._BODENHÖHE < 5 && my._BODENHÖHE > 0) { my._Bewegung_Vert = 0; my._absoldis_Z = 0; 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │27 } if (my._BODENHÖHE < 0 ) { force.z = -0.5 * my._BODENHÖHE; // Boden-Elastizität friction = 0.5; // Bodenreibung // Geschwindigkeit vertikal my._Bewegung_Vert = time*force.z + max(1-time*friction,0)*my._Bewegung_Vert; my._absoldis_Z = time * my._Bewegung_Vert; } } function Drift() { //// Kippbereich der Objekte //// if (my._dist_floorM <= 2 && (my._move_x == 0 && my._move_y == 0)) {return;} if(my.tilt != 0 || my._move_x != 0) { my._f_drift = my._gewicht * -sin(my.tilt); my._move_x = my._f_drift * time + max(1-time*friction,0)*my._move_x; my._absoldis_x = time * my._move_x; } if(my.roll != 0 || my._move_y != 0) { my._f_drift = my._gewicht * -sin(my.roll); my._move_y = my._f_drift * time + max(1-time*friction,0)*my._move_y; my._absoldis_y = time * my._move_y; } } function Kraftfaktor() { if(my._f_drift != 0) { my._move_force = 0; my._force = 0; } if(my._force > 0 || my._move_force > 0) { my._move_force = my._force * time + max(1-time*0.5,0)*my._move_force; my._force = 0; } } function Bewegung() { ent_nr = my.ent_id; if(my._move_force > 0) { my._absoldis_X = 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │28 (cos(ent_array1[ent_nr*10+8])*(my._move_force/ent_array1[ent_nr*10+6]))*time; my._absoldis_Y = (sin(ent_array1[ent_nr*10+8])*(my._move_force/ent_array1[ent_nr*10+6]))*time; } if(my._move_force <= 0 && my._move_x == 0 && my._move_y == 0) { my._absoldis_X = 0; my._absoldis_Y = 0; } move_mode = ignore_passable + activate_trigger + glide; ent_move(nullvector,my._absoldis_X); } 2. Vorstellung der Aktion 2.1 Die Aktion "action entity_1" //uses _Gewicht,_entity_x,_entity_y,_entity_z, action entity_1 { Koerper = my; // Zuweisung nur zu Testzwecken t += 10; // Erhöhung der Array Variablen ent_nr = t; // Speichern der Erhöhung my.ent_id = ent_nr; my.fat = off; // Speichern der Erhöhung in Entity Skill // Abschalten der dicken Hülle my.narrow = on; // Einschalten der dünnen Hülle //my.passable = on; if (my._gewicht == 0) // Zuweisung eines Gewichtes bei Null {my._gewicht = 10;} my.event = ent_col_event1; // Übergabe der Eventfunktion my.enable_sonar = on; // Sensibilisierung für Trace-Anweisung my.enable_shoot = on; // Sensibilisierung für Shoot-Event my.enable_block = on; // Sensibilisierung für Level-Kollisionen my.enable_entity = on; // Sensibilisierung für Entity-Kollisionen my.enable_impact = on; // Sensibilisierung für Entity-Kollisionen my.enable_push = on; // Sensibilisierung für Push-Event my.enable_click = on; // Sensibilisierung für Mausklick physik_1(); // Sprung in Hauptfunktion } Die erste Zeile, die mit //uses beginnt gibt diejenigen Parameter an, die wir später im WED unter Properties sehen, wenn wir der Entity die Aktion entity_1 zugewiesen haben. Als erstes wäre da unser Gewicht. Durch das Gewicht der Entity wird bestimmt in wieweit sie sich bei Kollisionen von ihrem ursprünglichen Platz wegbewegt. Die nächsten drei Angaben beziehen sich auf die tatsächliche Grösse der Entity. Bezogen auf die gesamte X-, Y- und Z-Ausdehnung der Entity. Sie können hier im WED die Werte eingeben. Sollten sie keine Angaben machen wird automatisch ein Gewicht von 10 kg und die Ausdehnung der Bounding Box genommen. So machen wir weiter mit der eigentlichen Aktion. Wir weisen der Entity den Namen Körper zu. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │29 Diese Zuweisung brauchen wir allerdings erst in einem späteren Tutorial, wenn es darum geht diverse Kisten und dergleichen zu stapeln. Dann haben wir die Erhöhung der Array Variable. Ich werde verschiedene Parameter, wie Kollisionspunkt, Kollisionsgeschwindigkeit und diverse andere Angaben in einem Array speichern um Entity Skills zu sparen. In den nächsten zwei Zeilen, ent_nr = t und my.ent_id = ent_nr speichere ich den Anfangsarray jeder Entity in einem Entity Skill ab um später jeder Zeit wieder darauf zugreifen zu können. Dann schalte ich die dicke Hülle der Entity ab und die dünne ein. Gefolgt von der vorher Besprochenen Gewichtszuweisung von 10 kg wenn keine Eingabe im WED statt gefunden hat. Die Zuweisung der Event Funktion, die Sensibilisierung für gewisse Event Aktionen und der darauffolgende Sprung zur Hauptfunktion physik_1 beendet dann unsere Aktion entity_1. 3. Vorstellung der Funktionen 3.1 Die Funktion "ent_col_event1()" function ent_col_event1() { if(event_type == event_impact) { if(my == null){return;} if(you == null){return;} ent_nr = my.ent_id; //// Koordinaten Trefferpunkt //// ent_array1[ent_nr*10+0] = target[0]; ent_array1[ent_nr*10+1] = target[1]; ent_array1[ent_nr*10+2] = target[2]; //// Koordinaten auslösende Entity //// ent_array1[ent_nr*10+3] = you.x; ent_array1[ent_nr*10+4] = you.y; ent_array1[ent_nr*10+5] = you.z; //// Gewicht der Entity //// if(you.skill1 == 0){temp = 10;} if(player == you){temp = 70;} ent_array1[ent_nr*10+6] = temp; //// Geschwindigkeit der Entity //// if(you.skill11 == 0){you.skill11 = 10;} ent_array1[ent_nr*10+7] = you.skill11; //// Winkel Aufprallrichtung //// // Wird noch nicht benötigt vec_diff(temp_1,target,you.x); //// Abprallwinkel //// vec_to_angle (temp,normal); ent_array1[ent_nr*10+8] = temp.pan; 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │30 ent_array1[ent_nr*10+9] = temp.tilt; //// Schiebende Kraft //// my._force = ent_array1[ent_nr*10+6] * ent_array1[ent_nr*10+7]; } if(event_type == event_shoot) { if(my == null){return;} if(you == null){return;} ent_nr = my.ent_id; //// Koordinaten Trefferpunkt //// ent_array1[ent_nr*10+0] = target[0]; ent_array1[ent_nr*10+1] = target[1]; ent_array1[ent_nr*10+2] = target[2]; //// Koordinaten auslösende Entity //// ent_array1[ent_nr*10+3] = you.x; ent_array1[ent_nr*10+4] = you.y; ent_array1[ent_nr*10+5] = you.z; //// Gewicht der Entity //// temp = you.skill4; ent_array1[ent_nr*10+6] = temp; //// Geschwindigkeit der Entity //// ent_array1[ent_nr*10+7] = you.skill5/2; //// Winkel Aufprallrichtung //// vec_diff(temp_1,target,you.x); //// Abprallwinkel //// vec_to_angle (temp,normal); ent_array1[ent_nr*10+8] = temp.pan; ent_array1[ent_nr*10+9] = temp.tilt; //// Schiebende Kraft //// my._force = ent_array1[ent_nr*10+6] * ent_array1[ent_nr*10+7]; } if (event_type == event_click) // Noch nicht in Verwendung { koerper = me; } } Die erste If-Anweisung bezieht sich auf die Kollision mit einer anderen Entity. Gefolgt von zwei Anweisungen die sich auf die my- und you-Entity beziehen, dort wird bei nicht vorhanden sein einer der beiden Entities die Funktion sofort verlassen um etwaige Empty Pointer Fehlermeldungen aus dem Weg zu gehen. Danach kommt der Aufruf der Array Nummer aus dem Entity Skill um die 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │31 ganzen speicherbaren Werte auch in den richtigen Array Bereich zu speichern und nicht etwa in den Array Bereich einer anderen Entity die mit dieser Kollision garnichts zu tun hatte. In den folgenden Array Variablen wird gespeichert, der Kollisionspunkt an der Entity, die X-, Y- und Z-Werte der kollidierenden Entity, das Gewicht und die Geschwindigkeit der Entity. Desweiteren die Winkelrichtung, die sich hier auf die Normale der Oberfläche beziehen. Und dann noch die Berechnung der Kraft die auf die Entity wirkt. Die Kraft berechnet man ja bekanntlich, wie jeder weiss der schon einmal Physik in der Schule gehabt hat, aus dem Produkt von Masse und Beschleunigung. my._force = ent_array1[ent_nr*10+6]*ent_array1[ent_nr*10+7] Was bedeutet, meine Geschwindigkeit ist dein Gewicht mal deine Beschleunigung. In der IfAnweisung der shoot-Abfrage befinden sich die selben Berechnungen und Abfragen die wir vorher schon besprochen haben. Nur die Gewichts- und Geschwindigkeitsangaben der Entity beziehen sich hier auf andere Skill Werte. Für die Gewichtsberechnung ist hier der Skill4 und für die Geschwindigkeitsberechnung der Skill5 der kollidierenden Entity zuständig. Diese Skills finden auch in den Templates Verwendung. Deshalb habe ich sie auch hier verwendet um Template Benutzer auch die Möglichkeit zu geben dieses Skript hier zu verwenden. Die letzte If-Abfrage bezieht sich auf das Anklicken der Entity mit der linken Maustaste. Diese Abfrage findet erst in einem späteren Tutorial Verwendung, wenn wir versuchen diverse Kisten oder Tonnen und dergleichen zu stapeln. 3.2 Die Funktion "physik_1()" function physik_1() { Max_Min_Berechnung(); if(my._entity_x == 0) { my._entity_x = my._MaxMin_x; } if(my._entity_y == 0) { my._entity_y = my._MaxMin_y; } if(my._entity_z == 0) { my._entity_z = my._MaxMin_z; } while(1) { Abstand_zum_Boden(); Abstand_Ecken(); Anziehungskraft(); Schieflage(); Drift(); Kraftfaktor(); Bewegung(); wait(1); 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │32 } } Die Hauptfunktion unserer Entity beinhaltet den Sprung in sämtliche andere Funktionen der Entity. Ich wähle immer diesen Weg der Hauptfunktion und den Sprung in die Unterfunktionen da es mir auf diesem Wege möglich ist eventuell bei bestimmten Aktionen verschiedene Funktionen der Entity zu überspringen. Ich gehe hier nicht im einzelnen auf die verschiedenen Funktionssprünge ein da wir die Funktionen noch genau besprechen werden. Hier nur eine grobe Auflistung der Funktionen und für welche Berechnungen sie zuständig sind. function Max_Min_Berechnung(); // Grenzen der Bounding Box function Abstand_zum_Boden(); // Abstandsberechnung zum Boden function Abstand_Ecken(); // Abstandsberechnung der Ecken der Entity zum Boden function Anziehungskraft(); // Anziehungskraftberechnung der Entity function Schieflage(); // Schieflage der Entity über Abgrund function Drift(); // Drift der Entity bei Schieflage function Kraftfaktor(); // Kraftfaktorberechnung bei Berührung der Entity function Bewegung(); // Bewegung der Entity Unterhalb des Funktionssprungs zur Max-Min Berechnung finden Sie die Zuweisung der Max-Min Parameter in die Entity_X Skills, diese Zuweisung findet statt wenn im WED keine Angaben der Ausdehnung der Entity gemacht werden. 3.3 Die Funktion "Max_Min_Berechnung()" function Max_Min_Berechnung() { my._MaxMin_x = (my.max_x - my.min_x); my._MaxMin_y = (my.max_y - my.min_y); my._MaxMin_z = (my.max_z - my.min_z); } Hier berechnen wir die Grenzen der Bounding Box der Entity. Diese Berechnung könnte man sich sparen, sie ist nicht unbedingt nötig. Aber dann müsste man jedesmal wenn man die Grösse feststellen will immer wieder die Berechnung my.max-my.min durchführen. So spare ich mir das und schreibe es in einen Entity Skill. 3.4 Die Funktion "Abstand_zum_Boden()" function Abstand_zum_Boden() { vec_set (temp,nullvector); vec_set(temp,my.x); temp.z -=4000; vec_set(temp_1,my.x); temp_1.z = my.z - ((my._entity_z)/2); trace_mode = ignore_me + ignore_sprites + ignore_models + scan_texture; // my._BODENHÖHE beinhaltet die Entfernung zum Boden my._BODENHÖHE = trace(temp_1,temp); 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │33 // my._floornormal auf die Normale des Bodens richten my._floornormal1_X = NORMAL.X; my._floornormal1_Y = NORMAL.Y; my._floornormal1_Z = NORMAL.Z; } Zuerst Überschreiben wir den temp Vektor mit Null, danach weisen wir dem Vektor die X-, Y- und Z-Werte der Entity zu und verändern den Z-Wert auf 4000 Quants unter der Entity. Als nächstes schreiben wir die Koordinaten der Entity in den temp_1 Vektor und verändern den ZWert so das sich der Punkt genau an den Füßen der Entity befindet. Nun die Angabe des trace_mode. Hier ignorieren wir die my Entity, Sprites, Modelle und scannen die Textur unterhalb der Entity. Ich verwende hier bewusst nicht use_box da es beim scannen durch kleinere oder größere Entities als die Bounding Box bzw. die Hülle zu ungewünschten und fehlerhaften Effekten kommen kann. Das Ergebnis des Trace wird dann in den Skill my._Bodenhöhe geschrieben. Die letzten drei Zeilen beziehen sich noch auf Winkel des Bodens unterhalb der Entity, also die Normale des Bodens. 3.5 Die Funktion "Abstand_Ecken()" function Abstand_Ecken() { //// Trace von Mitte nach unten //// vec_set(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorM = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); //// Trace von links nach unten //// vec_set(temp.x,vector(0,(my._entity_y/2),0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my.max_z - my.min_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorL = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); //// Trace von rechts nach unten //// vec_set(temp.x,vector(0,-(my._entity_y/2),0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorR = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); //// Trace von vorne nach unten //// vec_set(temp.x,vector((my._entity_x/2),0,0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorF = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │34 //// Trace von hinten nach unten //// vec_set(temp.x,vector(-(my._entity_x/2),0,0)); vec_rotate(temp.x,vector(my.pan,0,0)); vec_add(temp.x,my.x); temp.z = my.z - (my._entity_z)/2; trace_mode = ignore_me + ignore_passable + ignore_passents; my._dist_floorB = trace(temp.x,vector(temp.x,temp.y,temp.z-500)); } In dieser Funktion wird der Abstand von jeder Ecke der Entity zum Boden gemessen. Ich werde das ganze an Hand des Trace von links nach unten erklären. Die anderen Anweisungen basieren auf dem gleichen Prinzip. in der ersten Zeile speichern wir in die temp-Variable einen Vektor dessen Xund Z-Wert null sind und nur sein Y-Wert die Größe der halben Entity-Breite aufweist. Diesen Vektor drehen wir nun durch vec_rotate in Bezug auf den Pan-Wert der Entity. Nach der Drehung haben wir einen Vektor der 90 Grad nach Links steht mit der Länge der halben Entity. So, jetzt haben wir die Richtung des Vektors festgelegt. Was jetzt noch fehlt ist die genaue Lage, denn bis jetzt sitzt der Vektor noch auf dem Nullpunkt des WED. Um den Vektor in die richtige Endlage zu verschieben verwenden wir den Befehl vec_add. Wir addieren nun zu unserem Vektor den Vektor der Entity und schon sitzt der Punkt den wir haben wollten 90 Grad links neben unsere Entity. Nun noch den Z-Wert an den unteren Punkt der Entity verschieben und schon haben wir unseren ersten Tracepunkt festgelegt. Im trace_mode ignorieren wir diesmal wieder die my-Entity, Blocks die das passable-Flag gesetzt haben und Modelle und Sprites die auf passable gesetzt sind. Dann wird der Trace von unserem linken Punkt in eine Tiefe von 500 Quants ausgeführt und in den Skill my._dist_floorL übertragen. Das ganze führen wir von allen vier seitlichen Punkten und von der Mitte der Entity aus. 3.6 Die Funktion "Schieflage()" function Schieflage() { temp = abs(my._dist_floorF - my._dist_floorB); if(temp <= 1) { my.tilt = 0; my._f_drift = 0; } temp = abs(my._dist_floorL - my._dist_floorR); if(temp <= 1) { my.roll = 0; my._f_drift = 0; } if (my._dist_floorM <= 2) {return;} if (my._dist_floorM > 5 && my._dist_floorL > 5 && my._dist_floorR > 5 && my._dist_floorF > 5 && my._dist_floorB > 5) { return; 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │35 } if (my._dist_floorL >= 5) { temp = atan(my._dist_floorL/(my._entity_y/2)); if(temp > abs(my.roll)) // Absolutberechnung da Roll negativ ist { my.roll -= 1 * time; } } if (my._dist_floorR >= 5) { temp = atan(my._dist_floorR/(my._entity_y/2)); if(temp > my.roll) { my.roll += 1 * time; } } if (my._dist_floorF >= 5) { temp = atan(my._dist_floorF/(my._entity_x/2)); if(temp > abs(my.tilt)) // Absolutberechnung da Tilt negativ ist { my.tilt -= 1 * time; } } if (my._dist_floorB >= 5) { temp = atan(my._dist_floorB/(my._entity_x/2)); if(temp > my.tilt) { my.tilt += 1 * time; } } } Die Funktion Schieflage ist dafür da um Objekte, wenn sie über einen Abgrund geschoben werden und sich ihr Schwerpunkt verlagert, abrutschen zu lassen und sie nicht erst mit der Anziehungskraft in Berührung kommen wenn sie komplett darüber hinweg geschoben wurden. Als erstes die Berechnung der Deaktivierung der Schieflage und der Drift. Wenn der Bodenabstand zwischen den zwei Punkten der Entity, z.b. der Absolutwert der Differenz des äusseren linken und rechten Punktes der Entity, kleiner als 1 Quant ist werden der Tilt-Winkel der Entity und der Driftfaktor auf Null gesetzt. Die gleiche Berechnung findet für den vorderen und den hinteren Punkt statt. Danach kommen zwei Einträge, die die Funktion beenden. Einmal die Abfrage vom mittleren Punkt zum Boden. Wenn der Abstand kleiner 2 Quants ist wird die Funktion beendet. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │36 Das ist klar denn in diesem Fall wäre der Schwerpunkt nicht über dem Abgrund und im zweiten Fall die Abfrage alles Punkte der Entity nach unten, denn da würde ja der freie Fall nach unten vorliegen was eine seitliche Drift auch beenden würde. Als nächste folgt wieder die Abfrage der einzelnen Aussenpunkte der Entity ob diese mehr als 5 Quants vom Boden entfernt sind und die darauffolgende Berechnung des Neigungswinkels mit Hilfe des Arcustangens. Mit temp = atan(my._dist_floorL/(my._entity_y/2)) berechnen wir den Neigungswinkel der Entity. Neigungswinkel = Arcustangens(Abstand zum Boden Links / Halbe Entity Breite). Dies ist also der Neigungswinkel, den die Entity erreichen muss wenn sie über einen Abgrund geschoben wird. Es folgt nun die Abfrage ob der Neigungswinkel grösser als der momentane Winkel der Entity ist. Sollte das der Fall sein wird zyklisch der Wert 1 zum Winkel der Entity dazu addiert. Die Berechnung der Neigungswinkel der anderen 4 Eckpunkte findet auf die selbe Art statt. 3.7 Die Funktion "Anziehungskraft()" function Anziehungskraft() { // in der Luft? if (my._dist_floorM > 5 && my._dist_floorL > 5 && my._dist_floorR > 5 && my._dist_floorF > 5 && my._dist_floorB > 5) { force.z = -5; // Schwerkraft friction = 0.1; // Luftreibung // Geschwindigkeit vertikal my._Bewegung_Vert = time*force.z + max(1-time*friction,0)*my._Bewegung_Vert; my._absoldis_Z = time * my._Bewegung_Vert; } // Bis zu 5 Quant über dem Boden if (my._BODENHÖHE < 5 && my._BODENHÖHE > 0) { my._Bewegung_Vert = 0; my._absoldis_Z = 0; } // Eintauchen im Boden if (my._BODENHÖHE < 0 ) { force.z = -0.5 * my._BODENHÖHE; // Boden-Elastizität friction = 0.5; // Bodenreibung // Geschwindigkeit vertikal my._Bewegung_Vert = time*force.z + max(1-time*friction,0)*my._Bewegung_Vert; my._absoldis_Z = time * my._Bewegung_Vert; } } Kümmern wir uns nun um die Anziehungskraft, die ja bekanntlich auf jeden Körper wirkt. Als erstes Testen wir ob sich die Entity in der Luft befindet. Das überprüfen wir indem wir feststellen ob sich jeder Aussenpunkt mindestens 5 Quants über dem Boden befindet. Ist dies der Fall übergeben wir die Parameter der Schwerkraft und der Luftreibung und berechnen damit eine negative, da die Schwerkraft den Wert -5 hat, vertikale Bewegung. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │37 Die Berechnung, Strecke = Zeit * Beschleunigung, ergibt nun die absolute Z-Distanz der Entity. Im nachfolgenden Schritt, 5 Quant über dem Boden, gebe ich der Entity die Freiheit nicht genau auf dem Boden aufzusitzen sondern bis zu 5 Quant darüber zu bleiben. Der nächste Funktionsschritt bezieht sich auf das Eintauchen im Boden. Hier wird die Entity wieder aus dem Boden herausgezogen. Der Grundwert der Geschwindigkeit ist hier wieder negativ (force.z = -0.5), was bedeuten würde das wir bei der späteren Berechnung nocheinmal eine negative vertikale Bewegung hätten. Das ganze bekommt jedoch einen positiven Wert da der force.z-Wert mit der Bodenhöhe multipliziert wird und die ist sobald wir im Boden eintauchen negativ. Da bekanntlich Minus * Minus = Plus ist werden wir im Laufe der nachfolgenden Berechnungen durch den jetzt positiven force.z-Wert wieder aus dem Boden herausgedrückt. 3.8 Die Funktion "Drift()" function Drift() { //// Kippbereich der Objekte //// if (my._dist_floorM <= 2 && (my._move_x == 0 && my._move_y == 0)) {return;} if(my.tilt != 0 || my._move_x != 0) { my._f_drift = 1 * -sin(my.tilt); my._move_x = my._f_drift * time + max(1-time*friction,0)*my._move_x; my._absoldis_x = time * my._move_x; } if(my.roll != 0 || my._move_y != 0) { my._f_drift = 1 * -sin(my.roll); my._move_y = my._f_drift * time + max(1-time*friction,0)*my._move_y; my._absoldis_y = time * my._move_y; } } In dieser Funktion berechnen wir die Drift der Objekte bei Schräglage. Die Funktion wird verlassen, wenn der Abstand zum Boden von der Mitte der Entity kleiner gleich 2 Quant, die Driftbewegung in X-Richtung und die Driftbewegung in Y-Richtung gleich 0 sind. Als nächstes folgt die Abfrage ob sich die Entity schon in einer Driftbewegung befindet und wenn ja wird die Berechnung der Drift in die jeweilige Richtung fortgesetzt. Diese Berechnungen werden sowohl für den Tilt- als auch für den Roll-Winkel durchgeführt. 3.9 Die Funktion "Kraftfaktor()" function Kraftfaktor() { if(my._f_drift != 0) { my._move_force = 0; // Geschwindigkeit durch die Kraft my._force = 0; // Kraftfaktor } if(my._force > 0 || my._move_force > 0) { my._move_force = my._force * time + max(1-time*0.5,0)*my._move_force; my._force = 0; 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │38 } } Wenn Sie sich noch erinnern haben wir unseren Kraftfaktor my._force schon am Anfang des Tutorials kennen gelernt und zwar in der Berechnung: //// Schiebende Kraft //// my._force = ent_array1[ent_nr*10+6] * ent_array1[ent_nr*10+7]; Dies ist die Kollisionskraft die uns von den Objekten die mit der Entity zusammen gestossen sind mitgegeben wurde. In der ersten If-Anweisung wird überprüft ob im Moment eine Driftbewegung ausgeführt wird. Sollte dies der Fall sein werden der Kraftfaktor und die daraus resultierende Geschwindigkeit auf 0 gesetzt. Die nächste If-Abfrage überprüft ob noch eine Kraft auf die Entity wirkt und führt bei einem positivem Ergebnis die Berechnung der schiebenden Kraft fort und setzt den Kraftfaktor auf 0. Das Rücksetzen des Kraftfaktors bewirkt, dass nach dem Erreichen der maximalen Geschwindigkeit die Entity wieder bis auf 0 abgebremst wird. Was in der Realität für Kraftbewegungen genauso zutrifft. 3.10 Die Funktion "Bewegung()" function Bewegung() { ent_nr = my.ent_id; if(my._move_force > 0) { my._absoldis_X = (cos(ent_array1[ent_nr*10+8])*(my._move_force/my._gewicht))*time; my._absoldis_Y = (sin(ent_array1[ent_nr*10+8])*(my._move_force/my._gewicht))*time; } if(my._move_force <= 0 && my._move_x == 0 && my._move_y == 0) { my._absoldis_X = 0; my._absoldis_Y = 0; } move_mode = ignore_passable + activate_trigger + glide; ent_move(nullvector,my._absoldis_X); } Nun kommen wir zur letzten Funktion dieses Skriptes. Hier findet die Bewegung der Entity statt. Zuert lesen wir wieder die Array Nummer, ent_nr, aus unserem gespeicherten Entity Skill aus. Als nächstes überprüfen wir ob noch eine Kraftbewegung aktiv ist um damit die Entity mit ihren Absolutwerten zu verschieben. Die darauffolgenden zwei Zeilen beinhalten die Distanzberechnung in Absolutwerten. Das bedeutet das die Entity nicht relativ zu der Ausrichtung ihres Pan-Wertes bewegt wird. Ich möchte dies kurz an Hand des absoluten X-Wertes erklären. In unserem Array (ent_nr*10+8) steht der Winkel in dessen Richtung die Entity bewegt wird. Mit der mathematischen Berechnung, Ankathete = cos(Winkel) * Hypothenuse legen wir die X-Entfernung der Entity fest. Wobei die Ankathete die X-Verschiebung, der Winkel, der eingetragener Kollisionswinkel und die Hypothenuse die Geschwindigkeit durch das Gewicht der Entity multipliziert mit der Zeit ist. Ich diffidiere hier die Geschwindigkeit durch das Gewicht, da die Bewegung der Entity abhängig von ihrem Gewicht sein soll. Je schwerer desto kürzer der 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │39 Bewegungsweg. Genau dieselbe Berechnung führen wir bei der Y-Verschiebung aus. In der nächsten If-Anweisung überprüfen wir ob noch eine Verschiebung der Entity durch die Drift oder die Kraftbewegung ausgeführt wird uns setzen bei keiner ausübenden Bewegung die X- und YVerschiebung auf 0. Gefolgt wird das Ganze von der Angabe des move_mode und der anschliessenden Bewegung der Entity mit den Absolutwerten. Ich hoffe ich konnte Ihnen einen kleinen Einblick in die Welt der einfachen Physik vermitteln. In einem der nächsten Tutorials werden ich noch die Bewegung auf schiefen Ebenen, Rotation, das Hochheben und Stapeln von Fässern oder Kisten basierend auf diesem Physik-Skript besprechen. Für Fragen und Anregungen stehe ich Ihnen gerne unter meiner E-Mail Adr. aras_game@chefmail.de MFG ARAS14 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │40 Zum Kugeln oder: Der einfache weg zum nahtlosen UV-Gitter Willkommen zu meinem ersten Tutorial über Mapping und 3d-Modelle. Auf zwei Seiten werden Sie lernen, wie einfach es ist, eines der schwersten Objekte im Raum auf eine Fläche abzuwickeln und mit einer Textur zu versehen. Vorher sollte Ihnen aber klar sein, dass diese, wie jede andere Methode auch, ihre Probleme hat und keineswegs der ultimative Weg zum Glück ist. So eignet sich die Methode gut für NebelSpheres oder Asteroiden, weniger aber für Himmelskörper wie Globen oder Planeten, bei denen es auf die möglichst verzerrungsfreie Darstellung der Textur ankommt. Hier bleibt Ihnen wohl vorläufig nichts Anderes übrig, als Ihre Texturen von Hand einzupassen. Wir beginnen zunächst mit einem Ausgangsbild. Es ist weder kachelbar, noch für Kugeln angepasst. Für die Umwandlung des Bildes benötigen wir zwei kostenlose Plugins für Grafikprogramme wie beispielsweise Photoshop oder Paint Shop Pro, aber auch kostenlose Programme werden unterstützt. Besuchen Sie http://www.richardrosenman.com/software/downloads/, hier finden Sie auch die volle Liste der unterstützen Programme. Die benötigten Plugins heißen „Spherical Mapping Corrector" und „Tiler", laden Sie sie herunter und entpacken Sie die Zip-Archive in den Plugin- 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │41 Ordner Ihres Malprogrammes. 1) Laden Sie das Bild in Ihr Grafikprogramm. 2) Führen Sie das Plugin „Spherical Mapping Corrector" aus. 3) Nutzen Sie das Plugin „Tiler", um die rechten und linken Kanten nahtlos ineinander über gehen zu lassen, Sie können die Werte des Screenshots als Referenz nehmen: 4) Wickeln Sie Ihre Kugel mit einem Sphere-Mapping- Algorithmus in Ihrem 3d-Programm aus, so dass das Gitter wie im folgenden Bild aussieht: Sowohl Cinema4d und 3ds Max, als auch kostenlose bzw. kostengünstige Tools wie Wings3d, UltimateUnwrap/LithUnwrap oder Blender werden mit einem Knopfdruck damit fertig. Texturieren 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │42 Sie Ihre Kugel mit der soeben erstellten Map et voilà. Keine Pole, keine Nähte. Ein Wermutstropfen bleibt jedoch, streckenweise ist die Textur leicht verzerrt, somit sollte Ihre Map eine vernünftige Auflösung besitzen und keine Beschriftungen oder Ähnliches beinhalten. Felix Caffier 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │43 Jetzt gibt's auf die Ohren! Soundeffekte Teil 3 Herzlich willkommen zum dritten Teil des Soundeffekt Tutorials. Heute werden wir einen verwendbaren Sound designen, einen Schuss, um genau zu sein. Dieser hier passt am ehesten zu einer Maschinenpistole oder ähnlichem. Sie werden erfahren wie Sie den Sound erstellen, ihn bearbeiten und in die Engine einfügen. Und Sie werden vielleicht überrascht sein, wie simpel die Grundsätze mal wieder sind. Zusätzlich gibt es einige Tipps und Tricks zur Einbindung von Sounds in Gamestudio. Um dieses Tutorial durcharbeiten zu können benötigen Sie den „Soundforum Synth V 1.0", den Sie hier erhalten: http://www1.keyboards.de/soundforum.htm#dersynthesizer WARNUNG: Softwaresynthesizer können jeden möglichen und unmöglichen Ton erzeugen. Auch solche, die jenseits der Leistungsfähigkeit Ihrer Lautsprecher liegen! Seien Sie vorsichtig, beginnen Sie mit niedrigen Lautstärken und verwenden Sie bitte keine Kopfhörer. Der Schalldruck kann ungeahnte Ausmaße annehmen und zu Hörschäden führen! Ich übernehme keine Verantwortung für materielle und / oder körperliche Schäden die aus der Benutzung dieses Tutorials resultieren. Starten Sie den Soundforum Synth und wählen Sie die Voreinstellung „Basic Noise". Wenn Sie einige Tasten drücken, können Sie in der Tat ein Rauschen hören. Nun wollen wir daraus einen Schuss generieren. Um Sie nicht zu sehr zu verwirren, stellen wir erstmal alle Hüllkurvenregler auf null, ausgenommen die „Decay" Regler, die kommen auf 20. Schauen Sie sich das Bild dazu an: In der Filter Sektion stellen Sie bitte „Cutoff" auf 70 ein und „Env" auf 40. Es werden also nur tiefere Frequenzen durchgelassen, wobei die Hüllkurve des Filters auch etwas Einfluss hat. „K-Track" stellen Sie bitte auf Null, um unerwünschte Tonhöheneinflüsse durch das Keyboard auszuschließen. Nun müssen Sie etwas lauter machen, entweder am „Level" Regler des Synth oder an Ihren Boxen. Der Grund hierfür: Der Filter lässt nur noch tiefe Frequenzen durch. Da diese im hellen Rauschen nur sehr leise vorhanden sind, müssen Sie sie verstärken. Was da so ein wenig nach klopfen auf Holz klingt, ist Ihr Ausgangsmaterial für den Schuss! Nun wird es Zeit für eine bittere Pille: Der Soundforum Synth kann keine Sounds exportieren. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │44 Wenn sie über die Soundkarte abgenommen werden, klingen sie sehr verrauscht. Um Ihnen dennoch die Möglichkeit zu geben, den Sound fertig zu machen, habe ich mit Reaktor4 den gleichen Sound erstellt und hochgeladen. Sie finden sämtliche Dateien hier: http://home.arcor.de/braindamaged/soundtut3.zip Zusätzlich brauchen Sie noch das folgende Programm: http://www.audacity.de Dieses Programm dient zur Bearbeitung von Audiodaten. Genau daß, was Sie brauchen. Und obendrein kostet es keinen Cent! Stellen Sie sicher, daß ein Ogg-Codec auf ihrem System installiert ist. Nach dem starten von Audacity und öffnen der Datei „shot1.ogg" bietet sich Ihnen folgendes Bild: Der Sound ist immer noch recht leise und liegt in Stereo vor. Das ist nicht unbedingt gut. Für einen Schuß lohnt es sich nicht, auf Stereo zu pochen. Mono reicht hier völlig aus. Klicken Sie hierzu links neben der oberen „Tonspur" auf den Pfeil bei „shot1". Nun öffnet sich ein kleines Kontextmenü, in dem Sie „Stereotonspur aufteilen" wählen. Mit einem Klick auf das Kreuz der zweiten Tonspur löschen Sie diese. Nun ist nur noch eine übrig, die Sie über das Kontextmenü auf „Mono" setzen können. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │45 Wählen Sie „Bearbeiten" --> „Auswählen" --> „Alles". Dies ist nötig, um den Sound lauter zu machen. Wählen Sie nun „Effekt" --> „Verstärken": Klicken Sie auf „Ok". Nun ist der Sound wesentlich lauter. Wählen Sie mit der Maus den stillen Bereich vor dem Sound aus und löschen Sie ihn mit „Bearbeiten" --> „Auswahl löschen". Mit der stillen Stelle nach dem Sound verfahren Sie genauso. Nun ist der Sound auch schön handlich: Leider klingt er noch nicht überzeugend. Um ihm etwas mehr punch zu geben, schauen Sie mal unter „Effekt" --> „Tonhöhe (Pitch) ändern": Wählen Sie einen Wert von 40%. Wenn Sie damit schon zufrieden sind, können Sie den Sound als Ogg oder Wav exportieren. Ich rate Ihnen zu Ogg - sie sind wesentlich kleiner und kosten keine 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │46 Lizenzgebühren wie mp3. Das dazu ein extra Codec nötig ist, kann man verschmerzen. Spielen wir ein wenig mit dem Kompressor herum: Markieren Sie alles wenn dies nicht schon der Fall ist. Gehen Sie auf "Effekte" --> "Kompressor". Es ist wichtig daß Sie die Ansprechzeit auf 0,1 Sekunden stellen. Ansonsten spricht der Effekt zu spät an. Lassen Sie sich nicht täuschen, sollten Sie kaum einen Unterschied hören beim experimentieren mit diesem Effekt. In der Wiederholung als MG-Sound wirken sich auch kleine Änderungen aus. Starten Sie „shot.exe" und schauen Sie sich die wdl Datei an, um einen Eindruck davon zu bekommen, wie man den Sound einsetzen könnte. Vor allem mit der „snd_tune" Anweisung kann man einiges anstellen. Ich hoffe, es hat Ihnen Spass gemacht. Natürlich kann es dieser Sound nicht mit aktuellen Sounds aus der Spielebranche aufnehmen. Hierfür ist der Soundforum Synth nicht flexibel genug. Aber lassen Sie sich gesagt sein: Auch die Profis kochen nur mit Wasser. ;-) Letztlich wird nahezu jede Explosion und jeder Schuss aus Rauschen generiert. Ob es von einem Oszillator produziert wurde oder ursprünglich ein ganz anderes Geräusch (im wahrsten Sinne) war, ist nur eine Möglichkeit der Variation. Das nächste Mal werden wir uns mit der Verfremdung und Veränderung von bereits vorhandenen Sounds mit Audacity beschäftigen. Außerdem lernen Sie, wie Sie mit vertretbarem Aufwand gute Aufnahmen erstellen können. Ich wünsche Ihnen viel Spass bis dahin, Torsten Fock www.vulkanware.de Tipps und Tricks zur Einbindung snd_tune(handle, Volume, Freq, balance); Diese Anweisung hilft Ihnen, etwas Zufall in die Sache zu bringen oder Motorensounds zu steuern. Schauen Sie sich das folgende, kurze Script an: function play_crossfire { var sndhandle; sndhandle = snd_play(crossfire_snd, 100, 0); temp = random(20)+90; snd_tune(sndhandle, temp, temp, 0); } Hier wird direkt nachdem der Sound angestossen wurde seine Frequenz (und die Abspielgeschwindigkeit!) sowie die Lautstärke zufällig geändert. Dies eignet sich sehr gut für Kreuzfeuer, Querschläger, Explosionen u.s.w. Gehsounds zur Animation synchronisieren: -skill1 muß auf 1 gesetzt werden, wenn die Entity läuft. -skill2 ist in diesem Beispiel der animationszähler der Figur 0...100%. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │47 function char_sounds { while(me) { if(my.skill1 == 1) // ich laufe { snd_play(walk_1_snd, 100, 0); while(my.skill2 < 50){wait(1);} snd_play(walk_1_snd, 100, 0); while(my.skill2 > 0){wait(1);} } wait(1); } } Motorengeräusche: freq ist eine Variable, die von der Geschwindigkeit des Wagens beeinflußt wird. Wenn Sie es realer haben wollen, müssen Sie in ein aufwändigeres Script anfertigen, daß sich mit der "Drehzahl" der Reifen und dem Zustand der Gangschaltung beschäftigt. function tune_sound { var soundhandle; soundhandle = snd_loop(engine_snd, 100, 0) // oder ent_playloop benutzen, je nach Bedarf while(me) { snd_tune(soundhandle, 0, freq, 0); wait(1 ; } } var doppler_factor Kennen Sie die Variable "doppler_factor"? Sie dient dazu den bekannten Doppler-Effekt zu steuern. Je nach Wert (0-10) ist der Effekt weniger oder mehr ausgeprägt. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │48 Versionskontrolle mit Subversion mit Beispielen anhand einer 3D Gamestudio Demo-Applikation von Christian Behrenberg Vorwort Dieser Artikel sollte eigentlich kürzer werden als er tatsächlich wurde. Aber ich habe schnell gesehen, dass eine Auflistung aller basics rund um Subversion und eine knappe Erklärung, was man da macht, einfach nicht genug ist. Ich habe eine Einführung in die Revisionskontrolle eingefügt und anhand eines trivialen Beispiels mit dem 3DGS das ganze versucht, anschaulich zu machen. Literaturangaben und Quellen stehen am Ende des Artikels. Ich setze meine Hoffnungen darin, das wenigstens ein paar Leute von diesem Artikel profitieren. Viele Menschen, die sich mal kurz mit der Revisionskontrolle auseinandersetzen, sagen, dass es zuviel Aufwand sei. Vor allem bei kleineren Projekten und wenn man alleine arbeiten würde. Ich sehe das nicht so, weil mir das SVN eine Menge Sicherheit und Möglichkeiten bietet und mich durchdachter meine Projekte planen lässt. In der professionellen Softwareentwicklung ist eine RC (= Revision Control) unabdingbar, weil dadurch die Entwicklungszeit dramatisch verkürzt wird und dem Projekt eine nötige Stabilität und Flexibilität verliehen wird. Viele kleine bis große Projekte, die unglaubliches Potential haben, scheitern genau an diesem Punkt. Wissen und Erfahrung auf dem Gebiet des Projektmanagements und den entsprechenden Tools dafür ist für die meisten ein gigantischer Schritt auf dem Weg vom eher „dreckigen" oder „schluderigen" Weg der Projektführung (oder von Softwareentwicklung allgemein) zu einem erfolgreicheren Weg - der zum gewünschten Ziel führt. Zwar gehört dazu eine Menge eigener Einsatz (und vor allem der Wille!), aber wenn man weiß, was man machen kann, dann ist einem auch schon geholfen - vorrausgesetzt, man wendet es auch an ;) RC ist ein Standard in der Industrie und je früher man damit anfängt, desto besser ist das für sich selbst, für das Team, aber am meisten für das Projekt. Deshalb hoffe ich, dass der Leser das Potenzial sieht und nicht vor dem Artikel kapituliert - die investierte Zeit wird sich rentieren, ganz sicher. Einführung Typische Fehler in der Softwareentwicklung Wer mit Spieleprojekten vertraut ist, bei denen sehr viel Quelltext und sehr viel Content produziert wird, kennt so einige Situationen, in denen man fast verzweifelt, weil durch einen unglücklichen Umstand das komplette Projekt auf der Kippe steht. Vor allem aber passieren solche Vorfälle auch dann, wenn mehrere Leute an einem Projekt arbeiten. Hier nun einige Fälle, die Sie sicherlich schon einmal durchlebt haben: ✗ Irgendwas im am Ende bricht dann mühsam funktioniert das code funktioniert nicht, man sucht den Fehler, man baut zahlreiche Fixes ein und das ganze Programm ein. Nach etlichen Stunden oder Tagen Arbeitszeit hat man durch teilweise lückenhafte Backups den code wiederhergestellt und vielleicht Programm dann wieder - oder eben nicht. Das Projekt ist zum Scheitern verurteilt. ✗ Mehrere Programmierer haben an verschiedenen Spielmodulen gearbeitet und wollen nun alles zusammenfügen - ein heilloses Chaos. Denn wie es aussieht, hat jeder Programmierer irgendwo anders Modifikationen vorgenommen und man kann die neuen Sachen nicht einfach so zusammenfügen. Es geht viel Zeit verloren, nur um die Sachen lauffähig ins Spiel zu integrieren sofern jemand dazu in der Lage ist, das überhaupt zu bewerkstelligen. ✗ Es arbeiten mehrere Leute an einem Projekt und alle sind über das Internet verstreut. Jeder will die aktuelle Version haben, aber es gibt nur den Teamleiter, der immer den aktuellen Stand hat und 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │49 mal alle paar Wochen eine Version rausgibt, weil das immer so kompliziert ist mit dem Zusammenpacken aller Daten. Ist er verhindert oder krank, kann das Projekt nicht fortgeführt werden - alle müssen warten. ✗ Man kann nicht verfolgen, wer was wann gemacht hat. Wenn man dann beim Debuggen nach Fehlern sucht und genau wissen muss, wann wo welche Änderungen weshalb von wem gemacht worden sind - dann ist man meistens aufgeschmissen - weil es eben niemand weiß! ✗ Etc.pp. - typische Softwarefallen halt. Solche Fälle passieren zu Hauf während einer Softwareentwicklung. In solchen Fällen leidet das Team - und die Organisation bzw. die Projektverwaltung nimmt immer mehr Zeit in Anspruch als notwendig. Mit einer sogenannten Versionskontrolle sind aber alle diese Probleme gelöst. Was ist eine „Versionsverwaltung" und was hat das mit Spieleentwicklung zutun? Versionsverwaltung Unter einer Versionsverwaltung versteht man ein System, welches typischerweise in der Softwareentwicklung zur Versionierung und um den gemeinsamen Zugriff auf Quelltexte zu kontrollieren, eingesetzt wird. Das System hält dabei immer die Änderung der Datei(en) fest, wer sie bearbeitet hat und wann er das getan hat. Wogegen binäre Dateien (Bilder, Musik, etc.) immer komplett gespeichert werden, werden bei Textdateien (code, Dokumentation, etc.) immer nur die Unterschiede gespeichert, sodass man sich auch die Unterschiede anschauen kann - insbesondere dann nützlich wenn man schauen will, was man selbst oder jemand anderes im code eigentlich so verändert hat. Das ist sehr nützlich bei der Entwicklung von Programmen, Dokumentationen und Veröffentlichungen, insbesondere auch dann, wenn mehrere Entwickler daran beteiligt sind. Dabei wird sichergestellt, dass jeder Benutzer mit dem aktuellen Stand arbeitet oder auf Wunsch auf die archivierten Stände zugreifen kann. Dadurch ist eine Versionsverwaltung nicht nur für professionelle Entwickler in großen Teams, sondern auch für einzelne Entwickler interessant. Es kann jederzeit eine ältere Version aufgerufen werden, falls eine Änderung nicht funktioniert und man sich nicht mehr sicher ist, was nun alles geändert wurde - somit sind solche GAUs irrelevant, weil man jederzeit auf die letzte funktionierende Fassung zurückgreifen kann. Dadurch, dass man immer funktionierende Versionen in das System einfügt und anderen zugänglich macht, ist damit schlussfolglich auch immer sichergestellt, dass jeder Benutzer Zugriff auf die aktuell voll funktionsund lauffähige Version der Software hat. Anwendung bei Spieleprojekten Spieleentwicklungen sind technisch gesehen die anspruchsvollsten Softwareproduktionen überhaupt: man realisiert mehr oder weniger anspruchsvolle Softwarelösungen für die verschiedensten Anforderungen, die es in der modernen Softwareentwicklung gibt. Dazu kommt, dass heutezutage der Anteil des Grafik-contents immer beträchtlicher wird. Kein Wunder, dass an kommerziellen Spielen Dutzende Leute arbeiten, zum Teil in verschiedene Teams unterteilt und in diesen Teams Untergruppen mit verschiedenen Aufgabenbereichen. Auch kleine, unabhängige Produktionen beschäftigen mittlerweile ein Gruppe von Entwicklern, die zusammen an einem Spiel arbeiten. Solche Probleme, wie sie oben geschildert sind, wären wie ein halber Todesstoß für das Projekt. Viele Amateur-Entwickler schließen sich nun auch über das Internet zusammen, um gemeinsam an kleinen Spielen zu basteln. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │50 Die meisten Projekte scheitern allerdings, was statistisch gesehen durchaus plausibel ist: fehlende Erfahrung, keine Geldmittel für Tools und eine undurchdachte, fast chaotische Organisation kristalliert sich schon nach kurzer Zeit heraus. Man kann davon ausgehen, dass über 75% dieser „Projekte" den Bach runtergehen. Das liegt aber auch daran, das meistens nur eine, maximal zwei Personen Zugang zum source-code des Spiels haben. Das ist dann auch schon meistens der Haken, weil diese Person selber entwickelt und meistens keine Ahnung davon hat, was sie eigentlich zutun hat. Es entsteht kein echter Workflow, weil jeder nur über diese eine Person Zugang hat. Ein Revision Control System, z.B. „Subversion", löst aber alle diese Probleme (s.o.). Nun können alle Leute gleichzeitig an dem Spiel arbeiten, jederzeit eine aktuelle Version herunterladen, Zugriff auf alle Änderungen haben, zu unterschiedlichen Zeiten daran arbeiten und live neue Dateiversionen einspielen, wenn man zeitgleich zeitkritisch an einem bugfix arbeitet, etc. Grafiker können dann auch ihre Dateien unter Revision Control setzen, Änderungen durchführen und wenn Sie später feststellen, dass die aktuellen Änderung im Spiel schlecht aussehen, das ändern. Komplizierte Backupsysteme sind somit nicht mehr nötig und die Entwicklung kann viel dynamischer und viel sicherer stattfinden. Subversion und andere Tools Es gibt eine Reihe von Revision Control Software auf dem Markt, sowohl kommerzielle als auch kostenlose. Subversion ist ein Open Source Projekt und der inoffizielle Nachfolger von CVS. Es gibt auch einige Tools, wie z.B AlienBrain, die speziell auf content-reiche Projekte, wie eben Spieleproduktionen, ausgelegt sind. Allerdings kosten diese auch z.T. viel Geld. Es gibt eine Windows shell-extension für Subversion, „Tortoise SVN" genannt, welches in diesem Artikel vorgestellt und benutzt wird. Im Folgenden wird Subversion mit SVN abgekürzt. Download und Installation von Subversion auf einem Einzelplatz PC ✔ Besuchen Sie die Internetseite http://tortoisesvn.tigris.org/ ✔ Klicken Sie auf den Bereich „Download" (http://tortoisesvn.net/downloads) ✔ Es werden 32-bit und 64-bit Versionen vom SVN angeboten. Klicken Sie auf die entsprechende Installerfile. Sie werden automatisch auf die entsprechende Source Forge Seite re-directed, wo Sie automatisch die Installationsdatei herunterladen. ✔ Wenn Sie die Datei herunterladen haben, starten Sie sie und folgen Sie den Bildschirmanweisungen. Am Ende haben Sie das SVN und die Tortoise shell erfolgreich installiert. Eventuell müssen Sie den PC neustarten. Wie funktioniert das SVN? Eine kleine Geschichte Das SVN benutzt ein sogenanntes Repository. Diese Repository logged alle geänderten Dateien, Modifikationen im SVN, wer was wann gemacht hat. Wenn Sie einen neuen Ordner erstellen und dort die aktuellste Version der unter RC gestellten Dateien haben wollen, so ziehen Sie eine sogenannte Working Copy („WC") - dies impliziert, dass jede WC lauffähig und funktionabel ist. Stellen Sie sich nun vor, Sie sind Programmierer und wollen eine Änderung vornehmen, z.B. die Gegner in Ihrem Spiel intelligenter machen. Sie ändern die Dateien in der WC und wollen diese geänderten Dateien nun in das Repository hochladen (damit die anderen Entwickler des Spiels 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │51 auch Zugriff auf den geändert Code haben). Den Upload ins Repository nennt man „Commit". Das heißt, dass Sie ihre Änderungen dem System mitteilen. Es wird nicht nur ihre User-ID gespeichert, sondern auch wann sie commited haben und welche Dateien sie modifiziert haben (und wie). Sie können optional auch noch eine change-log Message einbauen, die einen Kurzüberblick gibt. Nehmen wir an, ihr Programmierkollege im Büro nebenan hat diesselbe Version der WC vm Firmenserver gezogen und hat nun auch im Gegnerskript was an der Animation geändert. Sie haben also die beiden gleichen Dateien bearbeitet, sie haben aber schon comitted. Was passiert nun, wenn ihr Kollege comitten will? Das SVN bemerkt diesen Conflict und teilt diese ihrem Kollegen mit. Er kann sich nun die Unterschiede von seiner zur neuen Version der Datei anschauen und entscheiden, welche Codeteile von ihm übernommen werden, welche von Ihnen entfernt werden oder welche Teile gemergedt (zusammengefügt) werden. Nach dem Commit von ihrem Kollegen (er teilt es Ihnen über einen Messenger mit), sind sie neugierig auf die neuen Animationen im Zusammespiel mit ihrer KI. Sie machen also ein Update und dabei werden die Änderungen (Changes) direkt in ihrer WC geändert. Sie freuen sich: es sieht gut aus und die Zusammenarbeit fand gleichzeitig ohne Probleme statt. Anmerkungen zum Multi-User System Im Folgenden wird Ihnen nun erklärt, wie sie selbst eine SVN RC auf ihrem Einzelplatz PC einrichten und bedienen. Wichtig: wenn Sie Subversion auf einem Server benutzen wollen, den Sie von überall aus erreichen wollen, so brauchen Sie einen Root-Server Account bei Ihrem Hoster oder einen eigene Server, weil Sie den Server entsprechend konfigurieren müssen. Daher wird in diesem Artikel nur auf die Einzelplatzbenutzung eingegangen. Weitere Details zur Benutzung des SVNs als Server finden Sie im OpenBook „Versioncontrol with Subversion" (http://svnbook.red-bean.com/). Wenn Sie im Netzwerk arbeiten, so können Sie Subversion auf einem Rechner einrichten und das Repository als Netzlaufwerk verbinden. Im Folgenden werden auch Situationen aus einem MultiUser Betrieb geschildert, allerdings trifft dies auch zu, wenn Sie alleine mit dem SVN arbeiten - es dient nur der Veranschaulichung. Damit Sie gleich die Benutzung im Zusammenhang mit dem 3DGS lernen, wird dies an einem Miniprojekt erläutert. Der normale Arbeitsablauf mit dem SVN - Features und Erklärungen Subversion hat viele Features, Optionen und viele Kleinigkeiten und Extras - aber im täglichen Betrieb werden Sie nur ein paar benutzen. Der typische Arbeitsablauf (oder -zyklus) mit dem SVN sieht so aus: • man updatet seine eigene Working Copy • SVN update • man macht seine Änderungen (neuer code, bugfixes, neue Grafiken, etc.) • SVN add (neue Dateien hinzufügen) • SVN delete (Dateien löschen) • man schaut sich seine Änderungen an • SVN status (Dateistatus (s.o.) abfragen • SVN diff (Unterschiede zur letzten oder einer anderen Revision angucken) • SVN revert (die geänderte Datei auf den letzten WC Stand bringen oder auf den Stand einer anderen Revision) • man merged seine Änderungen mit den Änderungen der anderen Entwickler 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │52 • SVN update (s.o.) • SVN resolved (bei Konflikten) • man commited seine Änderungen ins SVN Repository • SVN commit Das Repository Bevor wir nun das Spieleprojekt überhaupt starten, erzeugen wir uns ein leeres Repository, welches gleich die ersten Daten von der ersten unter RC gestellten Version unserer Demo enthalten wird. 1. Erstellen Sie in Ihrem Projekte-Verzeichnis (wenn Sie denn eins haben) einen Ordner für unsere SVN Demo. Ich habe ihn „SVNDemo" genannt. Erstellen Sie dort ein Verzeichnis, welches das SVN Repository beherbergt. In meinem Beispiel lautet der Ordner „SVNDEMO_REPO". 2. Klicken Sie mit der rechten Maustaste auf diesen Ordner. Sie sehen 2 neue Icons im Kontextmenü: „SVN Checkout" und „TortoiseSVN". Zeigen Sie auf „TortoiseSVN" und klicken Sie auf „Create repository here...". 3. Im folgenden Dialog werden Sie gefragt, welches Dateisystem Sie wählen wollen. Da uns das egal ist, bleiben wir beim „Native filesystem (FSFS)". Das Erstellen eines SVN Repository in diesem Ordner wird dann bestätigt. Glückwunsch! Ihr Repository ist nun eingerichtet. Bitte ändern Sie NICHTS in diesem Ordner, das wird später das SVN für Sie übernehmen. Bevor wir die erste Spielversion comitten, müssen wir erst eine erste Version überhaupt erstellen: 1. Erstellen Sie im Ordner „SVNDemo" einen temporären Ordner „temp" 2. Starten Sie den WED und erzeugen Sie einen hollow-cube und weisen Sie ihm die StandardTextur zu. Speichern Sie die Szene als room.wmp in diesem temp-Ordner und kompilieren Sie die WMB Datei. 3. Erzeugen Sie eine .wdl Datei in diesem Ordner und nennen diese „main.wdl". Weisen Sie diese WDL Datei dem Level zu. Schreiben Sie folgenden code in die WDL Datei: function main () { level_load("room.wmb"); wait(3); while (1) { camera.pan += 5 * time_step; wait(1); } } Wenn Sie das Level über den WED starten, dreht sich die Kamera andauernd im Kreis. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │53 Die soll unsere erste Version des Spiels sein. Ihnen werden alle Features vom SVN anhand dieses Beispiels erklärt. Nun wollen wir aber diese Version in das Repository als erste Version importieren: 1. Klicken Sie mit der rechten Maustaste auf den Ordner „temp". 2. Gehen Sie auf „TortoiseSVN \ Import...". Im folgenden Import-Fenster werden Sie zunächst dazu aufgefordert die URL des Repositories anzugeben. Da es sich bei Ihnen auf der Festplatte befindet, klicken Sie auf „..." und klicken Sich durch ihr System bis zu diesem Ordner. Markieren Sie ihn und klicken Sie auf OK. Im Textfeld müsste dann z.B. sowas wie „file:///I:/Projects/SVNDemo/SVNDEMO_REPO" stehen. 3. Bei jedem Import können Sie eine Import-Message anlegen. Geben Sie beispielhaft „SVN-Demo Repository eröffnet!" an. 4. Klicken Sie OK. Sie sehen dann, wie das SVN die Dateien in das Repository addet. 5. Nun löschen Sie den Ordner „temp". Er wird nicht mehr benötigt. 6. Erzeugen Sie nun den Ordner, unter dem Sie das unter RC stehende Spiel finden. Nennen Sie ihn z.B. „work". 7. Klicken Sie mit rechter Maustaste auf diesen Ordner und dann auf „SVN Checkout...". Sie müssen unter „URL of repository" ihr Repository angeben - i.d.R. wird das eben erstellte angezeigt. Klicken Sie auf HEAD Revision um den aktuellsten Status zu ziehen. Klicken Sie auf OK und sie sehen, welche Daten das SVN aus dem Repository holt. 8. Der „work" Ordner hat jetzt ein kleines grünes Häkchen, genauso wie jede Datei. Ein grünes Häkchen bedeutet immer, dass diese Datei seit dem letzten Abgleich mit dem Repository nicht verändert wurde. Glückwunsch! Sie haben gelernt, wie Sie ein Repository erstellen, eine erste Dateiversion unter Revisionskontrolle stellen und in ein Repository importieren. Außerdem haben Sie gelernt, wie Sie eine Working Copy beziehen. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │54 Dateien verändern und committen Wollen wir unseren Sourcecode ein wenig verändern. Sie stellen fest, dass der Kameracode lieber in eine eigene Kamerafunction gehört, die von der main function aufgerufen werden soll. Sie schreiben nun stattdessen: function cam(); function main () { level_load("room.wmb"); wait(3); while (1) { cam(); wait(1); } } function cam () { camera.pan += 5 * time_step; } Nachdem Sie auf „Speichern" geklickt haben, hat sich das Icon der Datei verändert: Das rote Ausrufezeichen signalisiert, dass die Datei verändert ist. Nun wollen Sie die Datei commiten, damit die Datei gesichert ist. Dazu klicken Sie mit der rechten Maustaste auf den „work" Ordner und dann auf „SVN commit ...". Im folgenden Fenster sehen Sie ein Feld für die Changelog, wo sie etwas eingeben können und ein Fenster, indem alle Änderungen angezeigt werden. Klicken Sie auf OK. Nun ist die Änderung im SVN verzeichnet. Ändern Sie nun wieder was im Code: schreiben Sie irgendwas rein, einen Kommentar zum Beispiel, und bauen Sie einen Fehler ein: //meine kleine Kamerafunktion function cam () { camera.pan += 0 * time_step; } Die Datei ist wieder mit einem roten Ausrufezeichen versehen. Nun, das Programm läuft nicht. Nehmen wir mal an, sie wissen nicht mehr was Sie verändert haben und wollen das jetzt wissen und nehmen wir mal an, sie wissen auch nicht mehr, welche Dateien Sie verändert haben. Klicken Sie einmal mit der rechten Maustaste auf den „work"-Ordner und dann auf „TortoiseSVN\\Check for modifications". Sie sehen dann einmal alle Änderungen auf einen Blick. Aha, Sie haben die Datei „main.wdl" geändert. Klicken Sie mit der rechten Maustaste auf die Datei und dann auf „Compare with base" - nun wird die Datei mit der letzten Version aus dem Repository verglichen. Dann sehen Sie folgendes: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │55 Sie sehen links die letzte Fassung aus dem letzten Update / WC und rechts die Änderungen. Zeilen mit einem + Zeichen weisen auf eine Änderung oder einer neuen Zeile hin und - (Minus-) Zeichen auf veränderte, bzw. gelöschte Zeilen. Sie sehen, das der Kommentar neu ist und das sie die camera.pan - Zeile geändert haben. Sie sehen, dass da eine 0 steht. Die Kamera dreht also nicht das ist der Fehler! - Ändern Sie ihn aber committen Sie ihn (vorerst) nicht. Neue Dateien, updates und merging Bevor jetzt weitere Features besprechen, ziehen Sie eine weitere Working Copy in den Ordner „work2". Dort müsste nun der fehlerhafte Code drin sein. In „work" haben Sie den ja schon korrigiert, aber noch nicht commited. „Work" hat also ein rotes Ausrufzeichen, während „work2" ein grünes Häkchen hat. Fügen Sie nun ein Sprite in „work" ein und stellen Sie diesen in ihr Level und kompilieren Sie die Levelfile erneut. Nun müssten ein paar level-Dateien ein rotes Ausrufezeichen haben. Der Sprite hingegen hat kein Symbol - die Datei steht nicht unter Versionskontrolle. Um diesen Sprite zu erfassen, klicken Sie mit einem Rechtsklick drauf und dann auf „TortoiseSVN\\add..". Die Datei hat ein blaues + Zeichen und wird beim nächsten Commit dem Repository hinzugefügt. Committen Sie diesen Stand des „work" Ordners. Stellen Sie sich vor, die WC im Ornder „work2" wäre auf dem PC eines anderen Programmierers. Der hat den Kamerafehler entdeckt und baut noch eine laufende Tilt-Veränderung ein: function cam () { camera.pan += 2 * time_step; camera.tilt += 1 * time_step; } Er hat weder den Kommentar eingebaut, noch diesen Sprite. Er denkt sich, bevor er committed: „vielleicht hat ja schon jemand weiter gearbeitet".. er macht also ein update, indem er mit rechter Maustaste auf seine WC klickt und dann auf Update klickt. Er sieht, wie die Sprite-Datei geaddet wird, die Levelfiles geupdated wird bei der Script-Datei - die er gerade bearbeitet hat, steht „merged" - was heißt das? Er guckt in die Datei und stellt fest, dass dort z.B. der Kommentar neu 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │56 ist. Das SVN ist in der Lage, neue Änderungen von außen (durch ein Update) zu erkennen und die geänderten Dateien anzupassen, sodass beide Versionen zusammengefügt werden. Der Programmierer von „work2" startet sein Programm und sieht seine neue Kamerarotation und den geupdateten Sprite. Er ist zufrieden und committet die neue Version. Dateien verändern Grundsätzlich gilt: alle Sachen, die man an einer Datei ändert, muss das SVN mitkriegen. Wenn Sie innerhalb vorhandener Dateien was ändern - die unter RC stehen - dann ist das ok. Wenn Sie aber - mit der Hand, also im Windows Explorer - Dateien löschen, umbenennen, verschieben o.ä., dann meckert das SVN. Dateien umbenennen Wir haben jetzt eine Date „sprite.bmp" in unseren Ordner getan, der im Level angezeigt wird. Wir wollen aber, das er anders heißt. Sie müssen jetzt über das SVN diese Datei umbenennen, sonst zeigt das SVN an, dass die Datei „sprite.bmp" fehlt und die umbenannte Datei wird als nicht RC stehend anerkannt - obwohl es ja prinzipiell die gleiche Datei ist. Klicken Sie mit der rechten Maustaste auf die Datei und dann auf „TortoiseSVN\\Rename..". Geben Sie im Dialogfeld „testSprite.bmp" ein. Durch ein blaues + Zeichen wird die Änderung signalisiert. Vergessen Sie nicht in der WMP Datei den Sprite abzugleichen und neu zu kompilieren. Dateien löschen Sie stellen fest, dass es in dem Ordner Dateien gibt, die Sie für das editieren des Levels nicht benötigen, weil sie sowieso immer automatisch erzeugt werden, wenn sie nicht vorhanden wären. Dazu gehören „*.bak" Dateien, als auch die Dateien „*.$$M", „*.$$w", „*.raw" und „*.wed". Markieren Sie alle diese Dateien und klicken Sie mit rechter Maustaste auf diese und dann auf „TortoiseSVN\\Delete". Die Dateien werden sowohl physikalisch aus dem work Verzeichnis entfernt als auch aus der Revisionskontrolle herausgenommen. Wenn Sie jetzt committen, wird das an das SVN Repository weitergegeben. Wenn ein anderer user jetzt ein update machen würde, würde das SVN bei ihm diese Dateien auch löschen. Dateien ignorieren Wenn Sie jetzt wieder an der WMP arbeiten, werden diese Dateien wieder erzeugt. Nun, es kommt darauf an, was unter RC steht - Ihnen ist es aber egal, ob diese Dateien bei Ihnen in der WC herumliegen. Sie können im SVN auch ignore-tags setzen, sodass das SVN diese Dateien „nicht sieht".. also ignoriert. Editieren Sie also die WMP (machen Sie den hollow cube größer oder so), speichern Sie die wmp ab und kompilieren Sie. Sie sehen dann, dass die neuen Dateien kein SVN Symbol haben: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │57 Logs Bei jedem Commit können Sie eine Log-Message eingeben, die gespeichert wird. Das ist dann besonders interessant, wenn Sie wissen wollen, was bei jeder Revision geändert wurde. Das können Sie auf das gesamte unter RC stehende Projekt tun, aber auch nur für Ordner und auch für einzelne oder mehrere Dateien. Klicken Sie z.B. mit der rechten Maustaste auf den Sprite und dann auf „TortoiseSVN\\Show log". Sie sehen dann z.B. Folgendes: Sie können einen Zeitraum der Log (für diese Datei in diesem Fall) angeben, von dem Sie auswählen wollen. Dann steht in einem Fenster jede Revision, in der die Datei geändert wurde, wer die Datei geändert hat, welche Actions auf die Datei ausgeübt wurde(n), wann dies getan wurde und eine Kurzform der log message. Wenn Sie einen Eintrag auswählen, wird die Log dann angezeigt. Repository Browser Man kann sich auch die aktuelle „Head" (= Kopf) Revisionstruktur im Repository anschauen, oder eben eine spezielle. Dort wird dann die Verzeichnisstruktur des Repositories angezeigt und alle dazugehörigen Daten wann was von wem wie verändert wurde. Hier nun ein Beispiel eines größeren Repositories von mir: 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │58 Wann soll man immer commiten? Im Prinzip könnte man sagen, das dies egal ist. Wenn man viele Änderungen oder ein großes neues Feature oder sowas einbaut, so sollte man immer in kleinen Häppchen commiten - damit bei evtl. Fehlern schnell wieder reverted werden kann. Wenn man eher immer große commits macht, dann kann man beim späteren Rekonstruieren eventuell die Übersicht verlieren, weil zuviel auf einmal gemacht worden ist. Reverten Das reverten ist eigentlich ganz einfach. Wir wollen nun einen einfaches Beispiel machen: nehmen Sie den Testsprite, laden Sie ihn in ein Grafikprogramm und malen Sie was darauf, sodass er verändert wird. Committen Sie die neue Version. Malen Sie nochmal was drüber, und committen Sie nochmals. Die neue Revision hat nun eine Nummer, z.B. 10. Der Sprite in Revision 8 war also der ursprüngliche Stand. Nehmen Sie einmal an, dass ist eine Textur oder so und Sie als Grafiker haben neue Versionen hochgeladen. Änderungen tätigen, nicht commiten, aber reverten Nehmen Sie an, sie zeihen nun ein update und wollen den Sprite verändern (tun Sie dies!). Sie stellen fest, dass die Änderung schlecht aussieht und wollen zum Stand der WC. Klicken Sie mit der rechten Maustaste darauf und dann auf „TortoiseSVN\\Revert...". Sie sehen dann alle geänderten Dateien (in diesem Fall der Sprite). Klicken Sie auf OK und die Datei ist auf dem alten Stand - sie ist reverted worden. Auf eine ältere Revision reverten und als neue Revision commiten Wenn Sie nun feststellen, dass die allererste Version, z.B. aus Revision 8, viel besser aussieht als alle nachfolgenden Revisionen (oder das ein code damals funktionierte und alle Neuerungen danach nur schlechte bugfixes waren) und sie wollen diese jetzt wieder - so geht das auch! Stellen Sie sicher, dass die Datei auf dem Stand der WC ist (bei einer Änderung also erst reverten). Gehen Sie dann im SVN Menü auf „Update to Revision" und geben Sie die gewünschte Revision an. Wichtig: die Datei ist dann nicht auf dem Stand der aktuellen Revision! Sie müssen dann den Dateiinhalt kopieren, die Datei wieder auf die Head-Revision bringen (auch mit „Update to revision") und die aktuelle Dateiversion mit dem Duplikat der „zurückgeholten" Datei überschreiben. Wenn Sie jetzt commiten, ist dann der Inhalt der „alten" Revision wieder „neu". Alte Dateien, die früher mal gelöscht wurden, wiederherstellen Sie können wie oben gezeigt, im Repository-Browser alte Revisionen anschauen. Wenn Sie nun eine alte Datei, die früher einmal gelöscht wurde, wiederherstellen wollen, dann suchen Sie sich zunächst die letzte bekannte Revision der Datei heraus. Dann können Sie im Repo-Browser - wenn sie diese Datei gefunden haben - die Datei irgendwo auf ihrem Computer speichern. Dann haben Sie die Datei wiederhergestellt! Ein Blick über den Tellerrand Dies sind nur die Basisoperationen, die Sie kennen müssen. Es gibt viele Ausnahmesituationen, denen Sie begegnen (z.B. conflicts, filelocks, etc.) werden, aber weitere Details dazu finden Sie im 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │59 oben genannten OpenBook. Wie Sie das SVN als server einrichten, steht dort auch - eine Erklärung wie man das macht und das SVN für diesen Betrieb einstellt, würde den Rahmen dieses Artikel bei weitem sprengen. Dazu gehört nämlich unter anderem der uneingeschränkte Zugang zu einem Server. Ich bezweifle das der durchschnittliche Leser einen solchen Besitzt oder Geld für einen Root-Server ausgibt. Wer aber die notwendigen Ressourcen hat, sollte sie aber auch anwenden: erst durch serverbasierte RC kann man ein echtes Projekt durchziehen, bei denen die Mitglieder einer Gruppe weit verstreut sind. Gerade bei internationalen Projekten mit Zeitzonen usw. ist das überaus hilfreich. Eine weitere Software, die ich in diesem Zusammenhang erwähnen will, ist das sogenannte TRAC, welches man mit dem SVN nahtlos kombinieren kann. Es ist eine Art Projektmanagement Software, die Aufgaben über Tickets verteilt, die bestimmten Personen zuteilen kann. Man kann auch bugreports einreichen, in den Tickets Diskussionen führen (z.B. wenn es um neue Features oder reporduzierbare bugs geht). Über sogenannten GANTT charts kann man Zeitpläne zur Projektrealisierung durchführen und anzeigen - und vieles mehr! Ich bedanke mich für Ihre Aufmerksamkeit, mit spielerischen Grüßen, Christian Behrenberg Literaturangaben Version Control with Subversion; open book. URL: http://svnbook.red-bean.com/ Subversion Website; URL: http://subversion.tigris.org/ TortoiseSVN Website; URL: http://tortoisesvn.tigris.org/ Wikipedia Artikel http://en.wikipedia.org/wiki/Revision_control http://de.wikipedia.org/wiki/Versionsverwaltung http://de.wikipedia.org/wiki/Subversion (Software) http://en.wikipedia.org/wiki/Comparison_of_revision_control_software Autorenwebsite: http://www.christian-behrenberg.de 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │60 Wings3d Tutorial Teil1 Hallo mein Name ist Ronny Leonhard und vielleicht kennt mich der ein oder andere aus dem 3DGS Forum. Ich möchte heute in meinem ersten Tutorial erklären wie man Wings3d so einrichtet das man damit vernünftig arbeiten kann. Wie gesagt das ist mein erstes und ich werde in weiteren erklären wie man damit modelliert und Texturen auf dem Modell auflegt, bis hin zum exportieren und importieren im WED. Kurz was zur Software selbst, Wings3d ist ein kostenfreies 3D Programm mit dem man 3d Modelle erstellen kann und auch für alles verwenden kann (darf). Downloaden könnt Ihr die Software bei www.wings3d.com. Start! Startet euer Wings3d, für denjenigen der mit 3ds Max und G-Max gearbeitet haben sollte, ist die Bedienoberfläche was neues, denn in Wings3d gibt's keine gleichzeitigen Ansichten von „Top, Front, Left, Perspektive" hier wird immer in einer Ansicht gearbeitet. Man kann die Ansichten aber umstellen, aber später mehr dazu. Jetzt seht Ihr ein Rastermuster und die Richtungsanzeigen „X, Y, Z", Ihr könnt das Rastermuster und die Achsen rechts oben aus und einblenden. Was beim Arbeiten manchmal sehr hilfreich sein kann. Damit man besser versteht was ich erklären möchte, erstelle ich einen „Cube" ( rechte maustaste -> Cube ). Der Cube ist erstellt und nun möchten wir auch gern die hinteren Seiten bearbeiten oder zumindest sehen können, also müssen wir den Cube drehen. Das funktioniert in Wing3d mit dem Scrollrad, einfach klicken und schon kann man den Cube drehen. Soweit so gut, nun ist aber unser Modell etwas länger und ragt über die Bildschirmlänge hinaus, also muss man das Modell etwas verschieben um den Rest sehen zu können. Das geht so ohne weiteres nicht, dazu muss man die Standardeinstellungen verändern damit dies auch geht. Preferences -> Camera und stell bei Camera Mode auf „ 3ds Max". -> „OK". 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │61 Jetzt können wir das Modell verschieben und das geht mit dem Scrollrad. Das Wenden und Drehen funktioniert fast immer noch genauso nur das Ihr zum Drehen jetzt die Taste „Alt" dazu mit benutzen müsst, also „Alt + Scrollrad" und schon könnt Ihr das Modell wieder drehen. Wer es mag kann auch die Hintergrundfarbe ändern, ich habe es bei mir gemacht weil ich es besser finde so zuarbeiten. Leider gibt's die Software nicht in deutsch aber wer polnisch oder schwedisch kann kann die Sprache umstellen. Es gibt auch noch andere Sprachen... So jetzt habt Ihr die optimalen Einstellungen um gute Ergebnisse zu produzieren. Im nächsten Tutorial erkläre ich wie man ein einfaches Modell erstellt. Viel Spaß beim modellieren! Ronny 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │62 Interview mit Ulf Ackermann, Gewinner des Conitec Spring Contests 2007 3dgs Magazin Dein Spiel hat den letzten Conitec Contest gewonnen. Es sprüht vor lustigen Ideen und Features. Was hat Dich zum Prinzip Utz Wollewutz inspiriert? Ulf Ackermann Ich habe einige Marble Madness Clones gespielt zu der Zeit. Da gab es zum Beispiel eins mit einem Hamster in einer Kugel. Allerdings fand ich das recht trist, da die Umgebung nur aus farbigen Quadraten bestand. Ich bin ein grosser Fan von Sonic. Da dachte ich mir, ich probiere einfach mal, das Marble Madness Spielprinzip mit Jump and Run Einlagen zu würzen! 3dgs Magazin Woher nimmst Du all die lustigen Ideen? Ulf Ackermann Nunja, die kommen mit der Zeit... Ausserdem ist einiges natürlich bewährt aus anderen Spielprinzipien, zum Beispiel die Powerups. Ich mag Schafe, das sind einfach lustige Tiere. Ich kann auch den Ton eines Schafes fast naturgetreu nachahmen, willst Du mal hören? ;-) 3dgs Magazin Vielen Dank für das Angebot. ;-) Du hast die Newton Physik Engine sehr kreativ eingesetzt. Kannst Du uns einige Tipps in Bezug auf die Verwendung von Newton mitteilen? Ulf Ackermann Anfangs, als ich noch eine überschauliche Anzahl an Physikobjekten hatte, machte Newton keinerlei Probleme. Hat man hingegen zuviele Objekte, kann es unter ungünstigen Bedingungen abstürzen. Man sollte auch keine zu komplexen Modelle als Newtonentities nutzen! Am besten verstreut man die Objekte, so dass maximal 4-5 auf einmal miteinander kollidieren können. Das ist gut für die Performance! Für Kollision mit anderen Objekten, welche keine Newtonentities sind, hat es sich bewährt ein "normales" Gamestudioentity auf der selben Postion mitzuführen und die Kollisionen bequem mit Events zu organisieren. 3dgs Magazin Das Spiel wirkt sehr sauber konstruiert und alles passt zusammen. Hattest Du einen Plan oder hast Du einfach losgelegt? Ulf Ackermann 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │63 Um ehrlich zu sein habe ich einfach angefangen. Ich hab mit Newton ein wenig herumgespielt und das machte mir einen Mordsspass. Ich wollte diese Sandkastenidee aufgreifen. Das man quasi viel umwerfen kann, Kettenreaktionen in Gang setzt und so weiter. Anfangs war Utz noch ein Igel. Mit der Zeit ist das Ganze gewachsen und das Resultat ist ein Schaf gefangen in einer Kugel was sich durch 30+ Level rollen muss. Gibt es eigentlich schon den Begriff Jump & Roll? 3dgs Magazin War dies Dein erstes Projekt? Ulf Ackermann Nicht wirklich. Ich habe schon eine Menge gemacht. Über manches bin ich im nachhinein nicht so stolz. Zum Beispiel gab es mal "Killerhuhn 3D", das erste Moorhuhn in 3D. Wenn ich mir das heute anschaue, ist es mir ein wenig peinlich. Zu meiner Verteidigung: Ich war damals erst 17 und es war mein erstes Projekt. Ansonsten hatte ich neben allerlei Experimenten einen Westernshooter/adventure angefangen. Screenshots davon gibt es noch in AUM 7. (http://www.coniserver.net/coni_users/web_users/pirvu/aum/aum7/english/images/danrecent_scr eenshots.jpg) 3dgs Magazin Hast Du schon Pläne für die Zukunft? Ulf Ackermann Allerdings. Ich werde auf jeden Fall bei Gamestudio bleiben. Weil ich glaube, daß ich als quasi Einzelkämpfer mit der Hilfe von ein paar guten Modellern nur als Casual-Game Entwickler eine Chance habe. Grosse Projekte werden es nicht - ich habe allerdings einige spassige Ideen für kleinere Spiele. Mehr möchte ich noch nicht verraten. 3dgs Magazin Was gefällt Dir an Gamestudio besonders gut? Ulf Ackermann Es ist "einfach", und läuft auf sehr unterschiedlicher Hardware nahezu absturzfrei. Das ist wohl das grösste Plus und sehr wichtig wenn man Spiele für eine breite Zielgruppe mit "älteren" Rechnern entwickeln möchte. Die Community ist wohl auch eine der besten, die mir über den Weg gelaufen ist bisher. 3dgs Magazin Und was findest Du eher nicht so toll? 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │64 Ulf Ackermann Der Multiplayerteil ist momentan noch sehr unkomfortabel. Es ist zwar grundsätzlich möglich ein Mehrspielerspiel zu entwickeln, allerdings ist der Aufwand extrem hoch. Der 2D Part gefällt mir auch noch nicht so (mein Menü hat ca. 5000+ Zeilen Code), ein Drag & Drop Gui Editor würde der Engine gut tun. Ausserdem sollte der Renderer etwas schneller werden. Die Map/Modelleditoren sind zwar okay, aber auch hier gibt es innovativere, nutzerfreundlichere Entwicklungen. 3dgs Magazin Was würdest Du Anfängern raten? Ulf Ackermann Lest meinen Blog (http://www.ackbytes.de)! ;-) Nein, quatsch. Ich rate ganz klassisch dazu, als erstes die Grundlagentutorials durchzuarbeiten. Danach sollte man sich ein total einfaches Spielprinzip hernehmen (z.b. Pacman, Asteroids, Snake...) und das probieren mit Gamestudio nachzubauen. Natürlich mit eigenen Änderungen/Ergänzungen. Man sollte es zuendebringen! Also selbst wenn es nur ein Level hat, ein komplettes Spiel daraus machen mit Installationsprogramm, Hilfedatei usw. Daraus lernt man enorm. Spieleentwicklung ist nicht nur Spass und dabei lernt man auch unangenehme Aufgaben zu erledigen. Vielen Dank an Ulf, daß er sich die Zeit genommen hat unsere Fragen zu beantworten! Das Interview wurde von Torsten Fock im Auftrag des 3dgs Magazins durchführt. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │65 Interview mit Sven Paroth, dem Zweitplatzierten im Conitec Spring Contest 2007 3dgs Magazin Du hast mit "Angelas World" ein sehr reizvolles Spiel entwickelt, dass unter anderem von seiner Einfachheit und Deinem besonderen Style lebt. Welches Programm hast Du benutzt um die stilvollen Grafiken zu erstellen? Sven Paroth Alle Grafiken wurden mit Adobe Photoshop CS erstellt, welches ich leider nur auf meiner Arbeit nutzen kann. An ungeduldigen Tagen hab ich dann Zuhause mit dem kostenlosen Programm "GIMP" gearbeitet. 3dgs Magazin Arbeitest Du mit einem Grafiktablett? Sven Paroth Nein. Da meine Grafiken alle nur einfarbig sind und ich jede Art von runden Formen vermeiden wollte, reicht da eine Maus aus. Ich finde es auch persönlich angenehmer mit dem "Pen-Tool" von Photoshop (erstellen von Pfaden) mit der Maus zu arbeiten, als mit einem Grafiktablett, da das Nachbearbeiten der Pfade präziser mit einer Maus ist (meiner Meinung nach). 3dgs Magazin Wie inspirierst Du Dich? Sven Paroth Wenn ich das wüsste... Ich kann das nicht erzwingen und mir sagen "so, jetzt denk dir mal was neues aus". Das muss einfach von selbst kommen. Inspirieren tun mich sicherlich so einige Sachen wie Menschen, Kunststile, Musik, etc... 3dgs Magazin Der Lohn dafür war der zweite Platz im letzten GS-Contest. Hast Du damit gerechnet? Sven Paroth Mit dem zweiten Platz hab ich auf keinen Fall gerechnet. Ich war mir zwar mittlerweile bewusst, dass das Spiel bei einigen Leuten gut ankam, aber als ich die Liste der teilnehmenden Projekte gesehen habe, hab ich nicht geglaubt unter die besten 5 zu kommen. Projekte wie Utz Wollewutz, Memowar oder ähnliches sind einfach umfangreicher als mein Projekt. Mir war´s besonders wichtig 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │66 zu sehen was man von meinem Projekt hält, egal ob positiv oder schlecht. Von daher bin ich sehr dankbar für den 2. Platz. 3dgs Magazin Du hast im Forum schon des öfteren davon geschrieben, dass Du manchmal ein kleines Motivationstief hast. Das geht uns allen so. Wie gehst Du damit um und wodurch steigerst Du Deine Motivation? Sven Paroth Ohja das Motivationstief... Ich denke das ist das Hauptproblem Nr. 1 bei mir und vielen anderen, was das scheitern an Projekten betrifft. Da sich meine Stimmung sehr häufig ändert und leicht von vielen Dingen beeinflusst wird, gabs bei mir wirklich Wochen bis gar Monaten wo ich absolut keine Motivation für irgendwelche Projekte hatte. Um das bei "Angelas World" zu ändern, hab ich eigentlich recht wenig getan. Neue Motivation hab ich aber aus den ganz vielen positiven Kommentaren zu meinem Projekt gewonnen. Sowas baut schon sehr auf. Im neuen Projekt, "Angelas World 2", hab ich allein die Motivation vom Vorgängertitel mit eingebracht. Zur Zeit läuft alles super und meine Motivation bleibt dauerhaft oben, was vor allem daran liegt, dass ich viel mehr plane als vorher, mir Milestones setze, und die richtige Musik beim arbeiten auswähle. 3dgs Magazin Standen alle Features des Spiels von vornherein fest oder hast Du "ins Blaue hinein" entwickelt? Sven Paroth Um ehrlich zu sein, nein. Das ganze Projekt basierte nur auf den Grundgedanken "Ich will ein Spiel FERTIGSTELLEN". Die Grundidee für das Spiel hat mir meine Freundin verschafft. Bei der Grafik habe ich vorher immer auf die "Masse" geschaut, was denen eventuell gefallen kann. Dadurch hab ich oft Probleme beim Umsetzen bekommen. Aus dem Grund wollte ich diesesmal einfach meinen persönlichen Stil nutzen und hatte bedenken das er bei niemanden gefallen finden würde. Mehr Planung gabs eigentlich nicht. Der Rest kam durch meine Laune und wurde einfach "ins Blaue hinein" entwickelt, um´s mal mit deinen Worten zu sagen. 3dgs Magazin Was gefällt Dir an Gamestudio besonders gut? Sven Paroth Besonders gefällt mir einfach die Möglichkeit, mit einfachen Mitteln in kurzer Zeit wirklich "brauchbare" Ergebnisse zu erzielen. Am Anfang kann man sich als Beginner mit Templates, fertigen Modellen und Scripten bereits kleinere Spiele zusammenbauen. Wenn man dann konkretere Projekte angehen möchte (egal welches Genre), schreibt man sich eben alles selbst, gerade mit der A7 Engine und Lite-C. Zudem gibt es eine super Community, die bei Fragen oft gute Antworten liefern, und durch Plugins das 3DGS immer weiter ausbauen. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │67 3dgs Magazin Und was findest Du eher nicht so toll? Sven Paroth Schlecht finde ich eigentlich nichts an 3DGameStudio. Leute, die dauernd die A6 Engine mit der Unreal 3 Engine oder ähnlichem vergleichen, haben einfach den Sinn für die Realität verloren. Es hat schon seine Gründe wieso Engines wie die Unreal 3 Engine mehrere tausende Dollar kosten. Es war auch mit Sicherheit nie das Ziel von Conitec, eine ähnliche Engine zu entwickeln. Meiner Meinung nach gibt es keine bessere Engine für Neulinge und Fortgeschrittene in der Games Industry als die A6 Engine. Man bekommt extrem viel für sein Geld und muss nur lernen wie man selbst an seine Ziele kommt. Die Engine allein macht das Spiel nicht qualitativ. Wer dann irgendwann mal reich ist und eine große Firma gründet, kann dann gerne zu den Königen der Engines greifen 3dgs Magazin Was würdest Du Anfängern raten? Sven Paroth Ich rate Leuten sich erstmal die Grundlagen mit der A6 Engine beizubringen. Dabei hilft es, das Manual, Tutorials oder einfach Scripte von existierenden Projekten anzuschauen. Dann kann man irgendwann anfangen, mit den Templates oder eigenen Scripten, kleine Spiele zu programmieren. Geht auf Freewareseiten, schaut euch kleine Spiele an und versucht das ganze mit der A6 Engine umzusetzen. Besonders wichtig ist hier bei die Planung! Um so früher man damit anfängt, desto schneller wird man für spätere, größere Projekte Design Dokus und Konzepte schreiben können. Ich hab ebenfalls viel zu oft gesagt das ich sowas nicht brauche, wie z.B. bei Angelas World. Das war der Hauptgrund für meine Motivationstiefs. Im zweiten Teil ist alles schriftlich festgehalten und man sieht direkt was realisierbar ist, was zu tun ist, wie Umfangreich das Projekt ist und kann so viel gezielter und Motivierter arbeiten! Und bitte, fangt garnicht erst mit MMORPG's oder des gleichen an. Sowas erfordert Jahre lange Erfahrung und ein professionelles Team. Im Namen des 3dgs Magazins bedanke ich mich ganz herzlich bei Sven "Kihaku" Paroth für die Beantwortung der Fragen. Das Interview wurde von Torsten Fock im Auftrag des 3dgs Magazins durchführt. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │68 Interview mit Johann Christian Lotter, dem "Vater" des 3D Gamestudios JCL gibt Antworten 3dgs Magazin Mit Lite-C schließen Sie eine Produktlücke und machen zugleich Gamestudio wesentlich flexibler. Wie kamen Sie auf diesen kleinen Geniestreich? Was hat Sie inspiriert? JCL Lite-C ist kein Geniestreich, sondern nur die logische Fortentwicklung einer reinen Skriptsprache zu einer Programmiersprache. C-Skript erlaubte nur Zugriff auf die Engine-Funktionen, lite-C dagegen Zugriff auf alle Softwarebibliotheken des PC, insbesondere die DirectX-Funktionen. Dies ist ein konsequenter Schritt für Gamestudio von einem reinen Spieleentwicklungssystem hin zu einem universellen Entwicklungssystem für alle möglichen Programme. 3dgs Magazin Vielen Usern mißfällt etwas die die Art, in der neue Features angekündigt werden. Einige hätten gerne einen "Fahrplan", nach dem sie die Entwicklung größerer Projekte hinreichend planen können. Auch wenn Sie verständlicherweise keine genauen Angaben machen können - wäre nicht eventuell eine grobe "Timetable" denkbar? JCL Diesen Wunsch kann ich verstehen. Wir haben im Büro ein grosses Whiteboard, auf dem Features mit Hilfe von Klebezetteln auf Termine verteilt sind. Diese Klebezettel lassen sich leicht abnehmen und neu gruppieren, und das passiert auch ab und zu. Eine feste Timetable hingegen hat die Eigenschaft, sich zu verselbständigen und das Kommando zu übernehmen. Entweder müsste ich mich strikt daran halten (schlecht für mich) oder sie immer wieder abändern (schlecht für User, die sich darauf verlassen). Deshalb lasse ich das lieber bleiben. Wir werden aber den Forecast umgestalten, so dass User besser erkennen können, in welchem Entwicklungsstand sich die verschiedenen Features befinden. 3dgs Magazin Was hat Sie dazu bewogen Lite-C und MED als Freeware anzubieten? (anm.: nicht für kommerzielle Zwecke) 3dgs Magazin Ich kann es mir natürlich nicht verkneifen und es muß ja auch sein... Können Sie uns irgend etwas über die Verbindung zu Atari mitteilen? Wir wollen uns doch nur für Sie freuen. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │69 JCL Es freut mich, wenn ich mit einer Antwort gleich zwei Fragen erledigen kann: Atari haben Sie es zu verdanken, dass lite-C und MED Freeware sind. Leider kann ich erst in ein paar Wochen mehr dazu sagen. 3dgs Magazin Sie haben eine besondere Art von Humor, die oftmals auf Logik begründet ist. Eigentlich schon ein Markenzeichen. Waren Sie - mit Verlaub - schon immer so? JCL Wer mich kennt, weiss, dass ich nicht besonders witzig bin. Der Spassvogel in unserem Team ist Doug. 3dgs Magazin Gibt es für Sie ein "Lieblingfeature" an der Acknex Engine? JCL Ja, ein eher unauffälliges Feature: das Template-System mit dem sich selbst editierenden Sourcecode per Kommentarmarken. 3dgs Magazin Wo sehen Sie Gamestudio in fünf Jahren? Haben Sie eine Vision? JCL Mit dieser Frage werden oft Kandidaten in Bewerbungsgesprächen genervt: Wo sehen Sie sich in fünf Jahren? Für Gamestudio hängt es davon ab, wie sich die PC-Hardware weiterentwickelt. In fünf Jahren haben wir die A8 Engine, die keinen Map-Compiler mehr benötigt und nicht nur das Rendern, sondern vermutlich auch Physik, Kollisionserkennung und Pathfinding per Hardware erledigt. Und wir haben ein Template-System, das automatisch viele Grundtypen von Spielen und Simulationen mit "Wizard"-Funktionen erzeugt. 3dgs Magazin Warum Hilbert´s Hotel? Warum die Unendlichkeit? Können Sie uns etwas über Ihre zweite Passion erzählen? JCL Warum die Unendlichkeit? Ich kann mir schlecht vorstellen, dass es jemanden gibt, den die Unendlichkeit gar nicht interessiert. Wer aber mehr wissen will, kann sich den Einleitungs-Sermon auf www.unendliches.net durchlesen. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │70 3dgs Magazin Mal anders gefragt: Gibt es einen Rat, den Sie ambitionierten und erfahrenen Entwicklern mit auf den Weg geben möchten? JCL Ambitionierte und erfahrene Entwickler brauchen keinen Rat von mir. Für weniger erfahrene Entwickler hätte ich den Rat, ihre Ambitionen solange zu zügeln, bis ihre Erfahrungen aufgeholt haben. Mit freundlichem Gruss jcl / Conitec Vielen Dank Herr Lotter, daß Sie sich die Zeit genommen haben auf unsere Fragen zu antworten. Das Interview wurde von Torsten Fock im Auftrag des 3dgs-Magazins durchgeführt. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │71 SEED_IT for 3DGS SEED_IT ist das hilfreiche Werkzeug für 3DGS, welches die Verteilung und Platzierung von Objekten (Modelle/Sprites/Entities) bei der Levelgestaltung einfach und komfortabel macht. Mit nur wenigen Mausklicks ist es möglich einen gesamten Level, eine Landschaft und vieles andere zu erstellen und zu verändern. Mit SEED_IT hat das langwierige Platzieren einzelner Objekte ein Ende. Aber SEED_IT kann noch mehr... Mit den zahlreichen Optionen kann die Sichtbarkeit, zusätzliche (benutzerdefinierte) Aktionen/Funktionen, die Positionierung, die Größe, das Aussehen, das Material, Bewegung und Animation, ..., der einzelnen Objekttypen schnell eingestellt und jederzeit verändert werden. SEED_IT generiert aus den Einstellungen performantes c-script welcher für spezielle Wünsche auch einfach erweiterbar ist. Wie funktioniert SEED_IT? SEED_IT verwendet je Objektplatzierung eine sogenannte SEEDMAP. Diese SEEDMAP ist ein einfaches Abbild der Objektverteilung anhand der drei Grundfarben: Jede der drei Grundfarben (R/G/B) repräsentiert dabei einen Objekttyp welcher wiederum aus bis zu zehn verschiedenen Modelle, Sprites, Entities bestehen kann. Der Farbwert (0..255) der einzelnen Grundfarben kann dabei auch noch die Dichte der Objektverteilung bestimmen. Die Verteilung der Objekte, welche sehr schnell in Echtzeit im Spiel durchgeführt wird, ist somit eine Projektion der Objekte nach der SEEDMAP auf das Terrain oder Modell (SEEDGROUND). Ein SEEDGROUND muss nicht zwingend sichtbar sein (z.B. bei Asteroiden). 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │72 Das Erstellen eines Levels in drei Schritten Zum Erstellen eines Levels mit SEED_IT sind nur drei Schritte notwendig: 1. Vorbereiten des Levels, auswählen der Modelle und erstellen der SEEDMAP. 2. Definieren der Objekttypen und deren Eigenschaften mit SEED_IT sowie das generieren des Scriptes mit einem Mausklick. 3. Einmalig das Einbinden des erzeugten Scriptes in das Projekt und auswählen der Seed-Action für das Terrain. Nachträgliche Änderungen am Leveldesign durch Neuplatzierung, Umsortierung, ändern der Modelle oder deren Eigenschaften ist dann nur noch eine Sache von Sekunden. Die Einstellungen in SEED_IT mit wenigen Mausklicks verändern, das Script neu generieren, und im Nu ist das Aussehen des Levels verändert. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │73 SEED_IT bietet aber noch viel mehr! - Aus-/einblenden der Objekte mit weichen Übergängen mit frei definierbarem Abstand - automatisches entfernen/erzeugen der Objekte zur Reduzierung des Speicherverbrauchs - Objektanimation oder -bewegung (Wind, Rotation, ...) - Einstellen der physikalischen Eigenschaften der Objekte (3DGS pro erforderlich) - Wettersimulation mit nur einem Schalter - einfache LOD-System Konfiguration - einfaches Einstellen des fog-Systems - Objektskills und -flags vordefinieren, Skins (fix/random Skin), Material (Material-LOD (einstufig)) - pixelgenaue Platzierung von einzelnen Modelle bis zur freien Verstreuung von vielen Modellen - und, und, und... Laden Sie sich die Demo herunter unter http://www.gameus.de und lassen Sie von nun an SEED_IT for 3DGS die Arbeit der Objektplatzierung übernehmen. SEED_IT for 3DGS Version 1.0 kostet nur € 25,- /~$33.Also nichts im Vergleich zu der Zeit für mühevolle manuelle Levelgestaltung. Vielen Dank an Ulrich "mercuryus" Seiffert für die Erklärung des Tools und die Bereitstellung einer Version für´s Autorengewinnspiel. 3D GAMESTUDIO-Magazin ■ Ausgabe 05 | Juni 2007 │74