Einführung in die Spiele Entwicklungsumgebung Blade3D
Lars Bilke, 06MIM, HTWK Leipzig, Fb IMN 01.08.2007
Inhaltsverzeichnis 1.
Einführung ....................................................................................................................................... 4 1.1.
Was ist Blade3D ....................................................................................................................... 4
1.2.
Architektur ............................................................................................................................... 4
1.3.
Funktionalität .......................................................................................................................... 5
1.3.1.
Interface zur direkten Manipulation ............................................................................... 5
1.3.2.
Visuelle Logik‐Diagramme ............................................................................................... 5
1.3.3.
Dynamisches Material‐System ........................................................................................ 5
1.3.4.
Skript‐System ................................................................................................................... 5
1.3.5.
Comunity‐Integration ...................................................................................................... 5
1.3.6.
Modell‐Import ................................................................................................................. 6
1.3.7.
Physik‐Sytem ................................................................................................................... 6
1.3.8.
Partikel‐System ................................................................................................................ 6
1.3.9.
Post‐Processing‐Effekte ................................................................................................... 6
1.3.10. Terrain ............................................................................................................................. 6 1.3.11. Makros ............................................................................................................................. 6 1.3.12. Trigger .............................................................................................................................. 6 1.3.13. Sound‐System .................................................................................................................. 6 2.
Programmoberfläche / Allgemeine Bedienung ............................................................................... 7 2.1.
3.
Werkzeugleisten und Menüs ................................................................................................... 7
2.1.1.
Szenen‐Werkzeugleiste ................................................................................................... 8
2.1.2.
Transformations‐Werkzeugleiste (Spatial) ...................................................................... 8
2.1.3.
Material‐Werkzeugleiste ................................................................................................. 9
2.1.4.
Beleuchtungs‐Werkzeugleiste (Lighting) ......................................................................... 9
2.1.5.
Kamera‐Werkzeugleiste .................................................................................................. 9
2.1.6.
Physik‐Werkzeugleiste (Dynamics) ................................................................................ 10
2.1.7.
Text‐Werkzeugleiste ...................................................................................................... 10
2.1.8.
Community‐Werkzeugleiste .......................................................................................... 10
2.1.9.
Hilfe‐Werkzeugleiste ..................................................................................................... 10
2.2.
Objektbrowser ....................................................................................................................... 11
2.3.
Eigenschaften‐Inspektor ........................................................................................................ 11
2.4.
Szeneneditor .......................................................................................................................... 12
2.5.
Skripteditor ............................................................................................................................ 13
2.6.
Tastaturkürzel ........................................................................................................................ 14
Mit Szenen arbeiten ...................................................................................................................... 15 2
3.1.
Standard‐Kamerasteuerung .................................................................................................. 15
3.2.
Szenenobjekte manipulieren ................................................................................................. 16
3.2.1.
Verschiebung ................................................................................................................. 16
3.2.2.
Skalierung ...................................................................................................................... 16
3.2.3.
Rotation ......................................................................................................................... 16
3.3.
4.
5.
6.
Werkzeuge zum Dupli‐zieren und Anordnen ........................................................................ 17
3.3.1.
Duplicate Grid ................................................................................................................ 17
3.3.2.
Duplicate SRT ................................................................................................................. 18
3.3.3.
Duplicate Around ........................................................................................................... 19
Materialien und Effekte ................................................................................................................. 20 4.1.
Unterschied zwischen Material und Effekt ........................................................................... 20
4.2.
Einen Effekt erstellen ............................................................................................................ 20
4.3.
Ein Material erstellen ............................................................................................................ 22
Verhalten integrieren .................................................................................................................... 24 5.1.
Logik‐Diagramme................................................................................................................... 24
5.2.
Skripte .................................................................................................................................... 25
5.3.
Makros ................................................................................................................................... 25
Soundsystem ................................................................................................................................. 27 6.1.
Samples und Sounds erstellen .............................................................................................. 27
6.2.
Sounds in der Szene verwenden ........................................................................................... 28
6.2.1.
Sound‐Trigger ................................................................................................................ 28
6.2.2.
Sound‐Skript .................................................................................................................. 28
7.
Blade3D‐Funktionalität erweitern ................................................................................................. 30
8.
Online‐Hilfe ................................................................................................................................... 32
9.
Tutorial: Pong‐Spiel ....................................................................................................................... 33 9.1.
Das Spielbrett ........................................................................................................................ 33
9.2.
Schläger erstellen .................................................................................................................. 35
9.3.
Schläger bewegen ................................................................................................................. 38
9.4.
Ball erstellen .......................................................................................................................... 42
9.5.
Ball bewegen ......................................................................................................................... 43
9.6.
GUI erstellen .......................................................................................................................... 48
Quellen: ............................................................................................................................................. 50
3
1. Einführung 1.1.
Was ist Blade3D
Blade3D von Digini Inc. ist eine neue 3D‐Spieleentwicklungsumgebung, die einen WYSIWYG‐ Szeneneditor, eine shaderbasierte Render‐Engine, eine C#‐basierte Skript‐Engine, einen fort‐ schrittlichen Texteditor, HLSL‐basierte Materialien und Effekte und eine Physik‐Simulation in einer einfach zu bedienenden Umgebung nahtlos vereint.
Wichtiger Hinweis: Blade3D ist ein recht junges Produkt und befindet sich noch im Beta‐Stadium. Die vorliegende Arbeit bezieht sich auf die Version Blade3D Beta 1 Refresh (Build 2213). Die Version kann unter www.blade3d.com heruntergeladen werden. Es kann also sein, dass bestimmte Funktionen in neueren Versionen nicht mehr funktionieren oder andere Auswirkungen als die hier beschriebenen haben. Blade3D hieß ehemals XNAMagic. Der alte Name war aber bereits rechtlich gesichert und das Produkt wurde deswegen umbenannt.
1.2.
Architektur
XNAFramework von Microsoft: XNA (XNA’s Not Acronymed) ist eine Technologie für die Spieleentwicklung für Windows XP/Vista und Xbox 360 von Microsoft und baut auf Teilen der DirectX‐Schnittstelle und des .Net Frameworks 2.0 auf. Es vereint wichtige Funktionen der Spieleprogrammierung in einem einfach zu programmierendem Framework und bietet erstmals die Möglichkeit ein‐ und denselben Quellcode sowohl auf dem PC als auch auf der Konsole Xbox 360 ausführen zu können.
Blade3D ist eine .Net‐Anwendung aufbauend auf dem XNA‐Framework von Microsoft und bisher lauffähig auf Windows XP SP2 oder Windows Vista (Unterstützung für die Xbox 360 ist in Entwicklung). Blade3D verfügt über eine erweiterbare, objekt‐orientierte Architektur. Das dyna‐ mische Objektmodell ermöglicht die Erstel‐ lung neuer Typen (Klassen) zur Laufzeit, bietet Serialisations‐Dienste (um z.B. konkrete Typ‐ Instanzen zur späteren Verwendung speichern zu können), Mehrfach‐Vererbung und ein Benachrichtigungssystem (um Daten bei Ereignissen zwischen den einzelnen
Programmteilen und Typen austauschen zu können). Dieses Objektmodell ermöglicht die Interaktion zwischen den einzelnen, isolierten Untersystemen. Das Objektmodell kann über Skripte gesteuert werden und stellt eine API für den Programmierer bereit, um auf alle Komponenten zugreifen zu können. So können z.B. Eigenschaften von mehreren
4
Objekten gleichzeitig verändert werden, Anfragen können gestellt werden, um an alle Objekte eines bestimmten Typs zu kommen und Felder und Basisklassen können zur Laufzeit hinzugefügt und entfernt werden. Um die Funktionalität von Blade3D zu erweitern braucht man nur einen neuen Typ in Blade3D definieren oder eine .Net‐Klasse schreiben. Die Klasse wird dann automatisch in die Entwicklungs‐ umgebung integriert. Wenn man nur einen Operator für ein Logikdiagramm schreiben will, dann brauch man nur eine statische .Net‐Funktion zu schreiben.
1.3.
Funktionalität
Hier folgt eine Kurzbeschreibung der Hauptfunktionalitäten von Blade3D. 1.3.1. Interface zur direkten Manipulation In der Entwicklungsumgebung können alle Objekteigenschaften in Echtzeit geändert werden. Veränderungen an Objekten über Eigenschaftseditoren werden unverzüglich an den Szenendesigner übermittelt. Alle Änderungen werden sofort sichtbar gemacht. Die Umgebung verfügt über Undo/Redo‐Funktionen ohne auf eine Neukompilierung angewiesen zu sein, wie es in der herkömmlichen Software‐Entwicklung der Fall ist. 1.3.2. Visuelle LogikDiagramme Neben der Unterstützung für traditionellere Wege Spiel‐Logik zu implementieren, wie C#‐basiertem Skripting und Integration mit anderen .Net‐Programmiersprachen, verfügt Blade3D über visuelle Logik‐Diagramme. Diese stellen den Datenfluss zwischen Objekten visuell dar und werden halbtransparent über die Szene gelegt, sodass Änderungen sofort sichtbar werden. Objekte werden einfach per Drag&Drop in das Diagramm gezogen und mithilfe von Operatoren miteinander verbunden. 1.3.3. Dynamisches MaterialSystem Die Rendering‐Engine von Blade3D gründet sich auf GPU‐basierten Shadern. Blade3D verfügt über einen Editor für Shader in HLSL mit Syntaxhervorhebung und Echtzeit‐Kompilierung bei gemachten Änderungen. Alle Änderungen sind sofort in der Szene sichtbar. 1.3.4. SkriptSystem Blade3D verfügt über ein C#‐basiertes Skripting‐System. Die Umgebung stellt einen Skript‐Editor mit Syntaxhervorhebung und Code‐Vervollständigung bereit. 1.3.5. ComunityIntegration Blade3D integriert die Online‐Community in die Desktop‐Applikation. Man kann direkt in der Umgebung Screenshots an die Community‐Webseite schicken, ganze Projekte oder nur einzelne Assets, wie Texturen oder Modelle, mit anderen Nutzern teilen. Außerdem können entdeckte Fehler im Programm in eine Bug‐Datenbank eingetragen werden. Das Blade3D‐Hilfesystem ist online‐basiert und wird dynamisch von Digini oder Community‐Mitgliedern erweitert. Das Hilfssystem beinhaltet eine Referenz‐Dokumentation, Beispiele, Assets und Video‐Tutorials.
5
1.3.6. ModellImport Zum Modell‐Import werden die Formate DirectX (.x), DarkBasic (.dbo), GameStudio (.mdl), Poser (.bvh), BlitzBasic (.b3d), Quake2 (.md2), HalfLife (.mdl und .smd), HalfLife2 (.smd), MilkShape (.ms3d), WaveFront (.obj) und 3ds Max (.3ds) unterstützt. 1.3.7. PhysikSytem Blade3D enthält ein einfaches Physik‐System, welches die Interaktion zwischen festen Körpern und auch die Interaktion mit Partikel‐Systemen, berechnet. 1.3.8. PartikelSystem Das Partikel‐System wird über Logik‐Diagramme definiert und gesteuert. Geometrische Grundkörper dienen als Emitter und als Kollisionsobjekte für die Partikel. Die Eigenschaften der Partikel‐Systeme können über vielzählige Operatoren miteinander verknüpft werden und sie können Eingaben von allen möglichen Objekten bekommen. 1.3.9. PostProcessingEffekte Post‐Processing‐Effekte wie Überzeichnung (Bloom), Sepia‐Tönung, Radialer und Gauss‐Weich‐ zeichner sind schon standardmäßig enthalten. Es können mehrere Effekte kombiniert werden und neue durch HLSL‐Shader integriert werden. 1.3.10. Terrain Die Terrain‐Engine arbeitet auf Grundlage von Höhentexturen (height maps) und benutzt eine Quadtree‐Implementierung, um Level‐Of‐Detail‐Unterstützung anzubieten. Ein spezieller Terrain‐ Shader ermöglicht die Texturüberblendung mit mehreren Texturen (z.B. für Gras, Schotter und Steine) mithilfe einer Kontrolltextur, die festlegt wie die einzelnen Texturen an bestimmten Stellen ineinander geblendet werden. 1.3.11. Makros Makros können neben den Logik‐Diagrammen und Skripten benutzt werden, um Spiel‐Logik einfach zu erstellen. Blade3D stellt eine Vielzahl an Makro‐Typen bereit, um Sounds abzuspielen, Animationen auszulösen, Werte zu interpolieren oder Ereignisse auszulösen. Mehrere Makros können in Verbund‐Makros (compound macros) zusammengefasst werden. Zufalls‐Makros (random macros) erzeugen nicht deterministische Effekte. 1.3.12. Trigger Ein Trigger wird durch einen Raum definiert (z.B. eine Kugel oder ein Quader). Kollidiert ein Objekt mit dem Trigger, so wird eine bestimmte Aktion, wie z.B. Abspielen eines Sounds, ausgelöst. 1.3.13. SoundSystem Das in Blade3D integrierte Audio‐Systeme ermöglicht den Import von Sounddateien in dem Format Wave (die Formate OGG, XM und MP3 sollen später noch unterstützt werden). Sounds werden durch bestimmte Ereignisse oder Skripte ausgelöst und können mit Effekten wie Chorus, Flanger oder Hall versehen werden, um eine realistische Soundkulisse zu erzeugen.
6
2. Program mmoberfläche / Alllgemein ne Bedien nung 2.1.
Werkzzeugleiste en und Me enüs
Nach dem Starten n von Blade3D über die angeleggte Desktop p‐Verknüpfung oder über den Startmen nüeintrag wird man aufggefordert seine Blade3D‐Accountdatten einzugeb ben. Man mu uss einen Account anlegen bevvor man Blade3D runterrladen kann.. Blade3D veerbindet sich h nun mit de er Online‐ nity sofern eeine Verbindu ung mit dem m Internet verfügbar ist. A Abbildung 1 zzeigt das Staartlayout. Commun
Abbildungg 1 ‐ Startlayout
Titelleistte Zeigt den n Namen des geöffneten n Moduls an. Dateime enü Das Dateeimenü öffn net sich beim m Klick auf das Blade3D‐‐Symbol in d der oberen liinken Ecke. Über das Menü kaann man Pro ojekte (Modu ule) im XML‐Format spe eichern und lladen oder ssogenannte Packages in einem m optimierten Binärformat laden. Weeiterhin zeiggt das Menü eine Liste der zuletzt ge eöffneten Module an. Hauptem menü‐Tabs Das Hau uptmenü ist die horizon ntale Leiste oben. Ein Klick auf ein nen bestimm mten Tab bringt b die zugehörige Werkzeu ugleiste zum m Vorschein n. Man kann n z.B. Grun ndkörper der Szene hin nzufügen, Objekte verschieben n oder das Material eines Objektes ändern. Man kann außerdem mit dem Scrollrad d der Maus d durch die untterschiedlich hen Tabs navvigieren.
7
Abbildungg 2 ‐ Hauptmen nü
Werkzeu ugleiste Die Werrkzeugleiste kann über einen e Doppeelklick auf die Tabs ein‐ und ausgeb blendet werd den. Jede Werkzeu ugleiste enthält Buttons für die am a meisten benutzten Kommando os in der je eweiligen Kategoriie. So enthältt z.B. die Belleuchtungs‐W Werkzeugleisste (Lighting)) Möglichkeiten der Szen ne Lichter hinzuzuffügen oder d die Farbe einer Lichtquellle zu ändern,, siehe auch Abbildung 3 3.
Abbildungg 3 ‐ Werkzeuglleiste (Licht)
2.1.1. SzenenWerkzeug gleiste
Hier kan nn man geom metrische Prrimitive wie Kugel und Q Quader der SSzene hinzufügen. Um eiin Objekt hinzuzuffügen reichtt ein Mauskklick auf deen jeweiligen Button. Das D Objekt erscheint sofort s im Szeneneeditor. Man kkann Modelle über
importieren n. Importierte Modelle w werden in ein ner Drop‐
Down‐Liste ausgewäählt . Deer Button fügt eine Instanz des ausgewählteen Modells d der Szene hinzu. In n der Displayy‐Spalte kan nn man die Anzeige derr Selektions‐Box, des Szeenenbodens und der Lichter an‐ a und aussschalten. In n der Bound ds‐Spalte kann man diee Anzeige deer Umgebun ngsboxen (boundin ng boxes) der d Objekte an‐ und au usschalten. Ein Klick au uf den Mutte‐Button stoppt die Wiederggabe von Sou unds. 2.1.2. Transfo ormationsW Werkzeugleiste (Spatial)
Hier sind d wichtige W Werkzeuge zu ur Objektmaanipulation zzu finden. In der Mode‐SSpalte wählt man die Transforrmationsart aus (Translaation, Skalieerung, Rotattion). Die drrei folgendeen Spalten enthalten e Eingabeffenster zur manuellen numerischen n n Einstellungg der Größe (Scaling), d der Rotation und der Lage im Raum (Tran nslation). Un nter Tools sind nützliche e Funktionen zu finden. Kamera direkt auf daas Objekt.
fokusssiert die
verschieebt das gewäählte Objekt direkt vor diie Kamera.
8
verschiebt das gewählte Objektt direkt nacch unten zur Koordinateenursprungssebene oderr auf das eingefüggte Terrain.
setzt alle Rotationeen des gewäh hlten Objektts auf Null zu urück.
2.1.3. Materia alWerkzeu ugleiste
M lte werden für f das ausggewählte Ob bjekt das Maaterial, die d diffuse, die spekulare s In der Material‐Spal und die Normal‐Textture gesetzt.. Klickt man aauf einen Bu utton, so sieh ht man ein D Drop‐Down‐M Menü mit verfügbaaren Materiaalien und Teexturen. Fäh hrt man mit der Maus über einen Eintrag so we erden die Auswirku ungen soforrt angezeigt.. Ein Klick auf den Eintrag setzt daas Material o oder die Textur. Die Farben‐SSpalte (Colorr) funktionieert genauso, nur das hierr die ambien nte, die diffuse und die sspekulare Farbe für das Objektt gesetzt werrden. 2.1.4 4. Beleuch htungsWerrkzeugleistte (Lighting g)
quellen erste ellen (Punkttlichter, Spo otlichter, dire ektionale In der Insert‐Light‐SSpalte kann man Lichtq w ge Projektio onslichter). Hat H man ein ne Lichtquellle ausge‐ Lichter, Projektionslichter und würfelförmig wählt so o kann man n in der Licchtfarben‐Sp palte (Light Colors) die ambiente, die diffuse und die spekularre Lichtfarbee einstellen. Beim Ankliicken bekom mmt man wieder w eine D Drop‐Down‐Liste mit möglicheen Farben inklusive Ech htzeitvorschaau. Unter Einstellungen (Settings) kann man die d Licht‐ Intensitääts‐Abnahmee (Attenuation) und die d Licht‐Reiichweite (Raange) einsteellen. Hat man ein Spotlichtt ausgewähltt, so kann man in der Winkel‐Spalte ((Angles) den n inneren und d äußeren Raadius des Lichtes einstellen, e s sowie unter Falloff den Intensitätsu unterschied zwischen diesen beiden n Radien einstelleen. 2.1.5. Kamera aWerkzeug gleiste
en. Beim Klick auf den zw weiten Butto on (Select Über Inssert kann maan der Szenee eine Kamerra hinzufüge Camera)) öffnet sich ein Menü mit m den verffügbaren Kameras. Fährrt man mit d der Maus üb ber einen Eintrag so s sieht man n die Szene aus Sicht diieser Kamera im Szenen neditor. Ein Klick auf den Eintrag wählt dieese Kamera als Aktive au us. Der letztee Button (Apply Lens Shaader) fügt deer Kamera ein nen Post‐ Processing‐Effekt zu. Auch hier h hat man einee Echtzeitvorschau aller vverfügbaren Lens‐Shaderr.
9
2.1.6. PhysikWerkzeuglleiste (Dynamics)
Über diee Physik‐Werkzeugleiste kann man O Objekte physikalische Eiggenschaften zuweisen. D Der erste Button (Make Activee Rigid Body)) fügt dem O Objekt Eigensschaften wiee Masse oderr Geschwindigkeit zu. n mit and deren Objekkten kollidieeren oder vvon der Sch hwerkraft Außerdeem kann daas Objekt nun angezoggen werden. Der zweite B Button (Makee Static Rigid d Body) entfeernt diese Eiggenschaften wieder. 2.1.7. TextW Werkzeugleiste
e ein neues Texttobjekt. In der Size‐Sp palte kann man die Der Einffügen‐Button (Insert) erzeugt Schriftgrröße über den Slider ein nstellen und d den dargestellten Textt eingeben. In der Family‐Spalte kann maan die Schrifttart mithilfe einer Echtzeeit‐Vorschau einstellen. 2.1.8. Commu unityWerk kzeugleiste
In der Co ommunity‐W Werkzeugleisste kann man n sich ein‐ un nd ausloggen n, einen Screeenshot macchen, der auf der Blade3D‐Weebseite veröfffentlicht wird oder eine en Bug meld den. Man kan nn den Bug in einem separateen Fenster beeschreiben u und dieser w wird dann in e einer Datenb bank gespeichert. 2.1.9. HilfeW Werkzeugleiiste
Ein Klickk auf den Fraagezeichen‐B Button öffneet die Online e‐Hilfe. Mit den d Pfeiltastten kann maan wie in einem Browser vor‐ und zurückn navigieren.
10
2.2.
Objektbrowser
Abbildung 4 ‐ Der Objektbrowser
Abbildung 5 ‐ Objektfilter auf Textur gesetzt
Der Objektbrowser stellt einen visuellen Überblick über alle Objekte in einem Modul zur Verfügung. Die Objekte sind in unterschiedliche Kategorien unterteilt, die durch einzelne Ordner repräsentiert werden. Über den Objekt‐Filter oben rechts kann man sich nur Objekte einer bestimmten Kategorie anzeigen lassen. Lässt man sich z.B. nur die Texturen im Browser anzeigen, so sieht man eine Vorschau der verfügbaren Texturen wie in Abbildung 5 dargestellt., Das aktuell ausgewählte Objekt ist blau hinterlegt. Der Name des Objekts wird außerdem in der unteren Statusleiste angezeigt. Man kann schnell die zuletzt benutzten Objekte im unteren Bereich des Objektbrowsers auswählen. Je heller ein Objektname, desto öfter wurde es bisher benutzt. Ein Doppelklick auf ein Objekt öffnet das jeweilige Eigenschaftenfenster.
2.3.
EigenschaftenInspektor
Alle Objekte in Blade3D verfügen über zahlreiche Eigenschaften, die ihre Erscheinung oder ihr Verhalten beeinflussen. Am leichtesten lassen sich diese Eigenschaften über den Eigenschaften‐ Inspektor bearbeiten. Diesen öffnet man, indem man auf das Objekt rechtsklickt oder im
11
Objektbrrowser auf das Objektt doppelklickkt. Es ersch heint nun ein e neues Fenster, welcches frei positioniert werden kann (siehe Abbildung 6).
Abbildungg 6 ‐ Der Eigensschaften‐Inspekktor
Oben reechts sieht man m den Naamen des Objektes O und d kleine Pfeile, um zwisschen den einzelnen e Kategoriie‐Tabs zu naavigieren. Eiggenschaften sind in Kateggorien grupp piert. Im Haup ptbereich weerden die Eiigenschaften n Zeile für Zeile aufgeführt. Je nach h Art der Eiggenschaft werden verschiedene Eingabemö öglichkeiten wie z.B. Texxtboxen, Slider, Farbwähler, Checkbo oxen oder own‐Menüs, angeboten. Drop‐Do Eigensch haften, die zwei z Objektee verbinden werden Objjektreferenzzen (ObjectR Ref) genanntt. So sind z.B. Matterialien Objeekte. Wenn man dann eein Material ändert, so äändern sich aauch alle Ob bjekte die das Matterial refereenzieren. Ob bjektreferenzzen werden im Inspekto or immer orange unterrstrichen. Wenn m man auf den LLink klickt, öfffnet sich das Eigenschafften‐Fenster des verlinkteen Objektes.. Wenn m man einen Weert über eineen Slider verrändert, so kkann man dieesen nur in vvorbestimmtten Wert‐ Bereicheen verändern n, die bei der Erstellung des Objektess festgelegt wurden. Maan kann aberr über die manuellee Eingabe dees Wertes im m Textfeld ein nen beliebige en Wert einggeben.
2.4.
Szenen neditor
Nach deem Starten von Blade3D nimmt deer Szenened ditor den größten Teil d der Anwend dung ein. Standard dmäßig wird d ein Bodengitter angezzeigt, um die Orientieru ung zu erleichtern. Die globalen Szeneneeigenschaften n erhält man n auf einen D Doppelklick auf den Scenee‐Ordner im Objektbrow wser.
12
In der Kategorie Szene (Scene) kann man die Materialien einstellen mit denen das Bodengitter gerendert werden soll und eine Standard‐Schriftart für eingefügte Text‐Objekte einstellen. Außerdem kann man die Schwerkraft definieren, die auf Objekte mit physikalischen Eigenschaften wirken soll. In der Kategorie Kamera‐Grundeinstellung (Camera Base) stellt man den Typ der Standardkamera und weitere wichtige Eigenschaften wie Blickwinkel und Seitenverhältnis ein und man kann der Kamera einen Post‐Processing‐Effekt zuweisen. In der Kategorie Viewport Base stellt man ein, welche Kamera für den Viewport, also die Ansicht des Szeneneditors, verwendet wird, welche Hintergrundfarbe verwendet wird (Clear Color), ob das Bodengitter gezeichnet werden soll (Draw Floor) und wie groß es sein soll (Floor Size und Grid Step) und ab welchem Knoten im Szenenbaum die Szene gerendert werden soll (Items, um bestimmte Teile der Szene vom Rendering auszuschließen).
Man kann Objekte über einen Klick auf den entsprechenden Button in der Werkzeugleisten zur Szene hinzufügen oder über einen Rechtsklick auf den Scene‐Ordner im Objektbrowser und dann Create/gewünschtes Objekt.
2.5.
Skripteditor
Das Skript‐System von Blade3D ermöglicht das Hinzufügen von Logik durch Skripte geschrieben in einem C#‐Dialekt. Szenen‐Objekte und Teile des Objekt‐Modells können über Skripte angesprochen werden und miteinander interagieren. Um einem Objekt ein Skript hinzuzufügen, klickt man mit der
13
rechten Maustaste auf das Objekt im Objektbrowser und wählt im erscheinenden Menü Add Script. Daraufhin sieht man ein Menü mit Eigenschaften des Objektes und Ereignissen an die das Skript gebunden werden kann. Ändert sich die Eigenschaft des Objekts oder wird das Ereignis ausgelöst, so wird das Skript gestartet. Wenn man z.B. MouseClick auswählt, wird das Skript gestartet wenn man mit der Maus das Objekt anklickt. Man öffnet den Editor, indem man auf den Tab Script Editor am unteren linken Rand der Anwendung klickt. Auf der linken Seite des Editors sieht man eine Liste aller erstellten Skripte. In der rechten Hälfte wird das Skript eingegeben. Das Skript wird auto‐ matisch gespeichert und kompiliert, wenn man in einen anderen Bereich der Anwendung klickt oder durch Drücken von F12. Der Editor ist an den Editor von Visual Studio angelehnt und bietet farbliche Syntax‐Hervorhebung, Code‐Vervollständigung und Fehler‐Hervorhebung.
2.6.
Tastaturkürzel
Taste F1 Strg + F Strg + N Strg + O Strg + S Strg + D Entf F10 F3 F4 F5 B F
Aktion Globale Aktionen Hilfe Hauptmenü Neues Modul Modul öffnen Modul speichern Objektbrowser Objekt duplizieren Objekt löschen Transformationstools Zurücksetzen aller Transformation Zurücksetzen der Skalierung Zurücksetzen der Rotation Zurücksetzen der Translation Verschiebt das Objekt vor die Kamera Fokussiert die Kamera auf das Objekt
G T V W S A D C W S A D X W S A D
Bewegt das Objekt auf das Bodengitter Bewegt das Objekt auf das Terrain Aktiviert Translations‐Modus Bewegt Objekt hoch Bewegt Objekt runter Bewegt Objekt nach links Bewegt Objekt nach rechts Aktiviert Rotations‐Modus Rotiert Objekt vorwärts um die X‐ Achse Rotiert Objekt rückwärts um die X‐ Achse Rotiert Objekt links um die Z‐Achse Rotiert Objekt rechts um die Z‐Achse Aktiviert Skalierungs‐Modus Skaliert das Objekt größer auf der Y‐ Achse Skaliert das Objekt kleiner auf der Y‐ Achse Skaliert das Objekt kleiner auf der X‐ Achse Skaliert das Objekt größer auf der Y‐ Achse
14
3. Mit Szenen arbeiten 3.1.
StandardKamerasteuerung
Abbildung 7 ‐ Standard‐Kamerasteuerung
Erstellt man eine neue Szene, so ist eine Standard‐Kamerasteuerung bereits durch ein Logik‐ Diagramm aktiv. Zum Verschieben der Kamera nutzt man die z.B. für einen Shooter typische Steuerung über die WASD‐Tasten. Mit den Tasten Q und E kann man die Kamera runter und hoch bewegen. Hält man die mittlere Maustaste gedrückt und bewegt man die Maus, so verändert man die Blickrichtung der Kamera. Ist ein Xbox 360 Gamepad angeschlossen, so kann man mit dem linken Analog‐Stick sich nach links/rechts und vorn/hinten bewegen. Mit dem rechten Analog‐Stick kontrolliert man die Blickrichtung. Hinweis: Die Standard‐Kamera ist außerdem ein Active Rigid Body, d.h. sie kollidiert mit anderen Objekten, denen physikalische Eigenschaften zugewiesen wurden, wie z.B. dem Bodengitter. Man kann die Steuerung über das Logik‐Diagramm DefaultControllerGraph (siehe Abbildung 7) im Ordner Graphs im Objektbrowser verändern und anpassen oder gleich eine komplett neue Kamerasteuerung implementieren.
15
3.2.
Szenenobjekte manipulieren
Um ein Objekt zu verändern muss man es erst auswählen. Dazu reicht ein einfacher Klick auf das Objekt im Szeneneditor oder im Objektbrowser. Wenn ein Objekt ausgewählt ist, so wird es von einer roten Box umgeben (dem Hüllquader). Es ist möglich mehrere Objekte auszuwählen, indem man die Strg‐Taste gedrückt hält während dem man die Objekte über Mausklicks auswählt. 3.2.1. Verschiebung In den Translations‐Modus gelangt man durch Drücken der Taste V oder durch Anklicken des Translate‐Buttons in der Spatial‐Werkzeugleiste. Danach erscheinen farbige Achsen‐Markierungen (mit einem Pfeil am Ende) am ausgewählten Objekt. Um das Objekt zu verschieben kann man die WASD‐Tasten oder die Maus benutzen. Mit der Maus klickt man auf das Objekt und zieht die Maus bei gedrückt gehaltener Taste an die gewünschte Position. Dabei bleibt die Ursprungsposition durch die Achsen‐Markierungen sichtbar, um eine bessere Vorstellung der Verschiebung zu erhalten (siehe Abbildung 8) Klickt man beim Verschieben direkt auf eine Achse, so verschiebt man das Objekt nur entlang dieser Achse. 3.2.2. Skalierung In den Skalierungs‐Modus gelangt man durch Drücken der Taste X oder durch Anklicken des Scale‐ Buttons in der Spatial‐Werkzeugleiste. Auch hier erscheinen wieder farbige Achsen‐Markierungen (mit einer Box am Ende) am ausgewählten Objekt und man skaliert nun analog zur Translation über die WASD‐Tasten oder die Maus. Man skaliert allerdings immer nur entlang einer Achse. Mit der linken Maustaste ist dies die X‐ Achse, mit der mittleren Maustaste die Y‐Achse und mit der rechten Maustaste die Z‐Achse. 3.2.3. Rotation In den Rotations‐Modus gelangt man durch Drücken der Taste C oder durch Anklicken des Rotate‐Buttons in der Spatial‐ Werkzeugleiste. Im Rotationsmodus werden die Rotationsachsen durch farbige, kreisförmige Bänder dargestellt (siehe Abbildung 10). Die Rotation erfolgt analog zur Skalierung über die einzelnen Maustasten.
Abbildung 8 ‐ Verschiebung
16
Abbildung 9 ‐ Skalierung
Abbildung 10 ‐ Rotation
Alternativ kann man die Transformationen auch numerisch über den Eigenschaften‐Inspektor des jeweiligen Objektes in der Kategorie Local Transform und Spatial eingeben. Local Scale, Rotation und Position sind dabei immer relativ zum übergeordneten Objekt in der Szenenhierarchie. Wenn Objekte die Eigenschaften von übergeordneten Objekten nicht erben soll, so muss man im Eigenschaften‐Inspektor in der Kategorie Spacial unter Inherit die entsprechenden Häkchen entfernen.
3.3.
Werkzeuge zum Dupli zieren und Anordnen
Blade3D stellt einige Werkzeuge zum duplizieren und anordnen von Objekten nach bestimmten Parametern bereit. Um die Werk‐ zeuge zu nutzen, klickt man im Szeneneditor mit der rechten Maustaste auf das Objekt und wählt im aufklappenden Menü das Werkzeug aus. 3.3.1. Duplicate Grid Dieses Werkzeug erzeugt mehrere Instanzen von einem Objekt und platziert diese auf einem Gitter.
Abbildung 11 ‐ Duplicate Grid
17
Die Parameter Spalten und Zeilen (Columns und Rows) bestimmen die Anzahl der Duplikate. Item Spacing bestimmt den Abstand der einzelnen Duplikate. Über die verschiedenen Variation‐Parameter kann man die Größe und die Rotation der erzeugten Objekte zufällig bestimmen.
Abbildung 12 ‐ Duplicate Grid 5x5 mit Größenvariation
3.3.2. Duplicate SRT Dieses Werkzeug erzeugt Instanzen von einem Objekt und setzt die Positions, Rotations‐ und Skalierungswerte in Abhängigkeit der angegeben Schrittweite. Die Schritt‐ weiten werden jeweils zu der Position, der Rotation und der Skalierung jeder neuen Instanz hinzuaddiert. Auch hier kann man die Schrittweiten über die Variation‐ Parameter variieren. Der Parameter Count bestimmt die Anzahl der Instanzen.
Abbildung 13 – Duplicate SRT mit 8 Instanzen und kleiner werdender Skalierung
Abbildung 14 ‐ Duplicate SRT
18
3.3.3. Duplicate Around Dieses Werkzeug erzeugt mehrere Instanzen eines Objekts und platziert sie zufällig um ein anderes Objekt in der Szene.
Abbildung 15 ‐ Duplicate Around mit 8 Instanzen (Kugeln) und Radius 4 um einen Kegel
19
4. Materialien und Effekte 4.1.
Unterschied zwischen Material und Effekt
Materialien werden in Blade3D genutzt, um Effekte zu konfigurieren. Ein Effekt kann von mehreren Materialien genutzt werden. Das Material definiert Einstellungen, um mit dem Effekt einen bestimmten Look zu erzielen. So ist in Blad3D z.B. der Standard‐Shader VertexLit.fx enthalten. Dieser Shader kann Objekte in einer beliebigen Farbe zeichnen. Ein Material, welches nun diesen Effekt benutzt, gibt die zu verwendende Farbe an. Der Shader kann nun unter Verwendung der Einstel‐ lungen im Material, der Objektdaten (also die Koordinaten der zu zeichnenden Vertizes) und weiterer globaler Parameter das Objekt zeichnen.
HLSLEffekt: Einem Effekt liegt eine .fx‐Datei zugrunde. Diese Datei enthält einen HLSL‐Shader (High Level Shading Language) und alle seine Parameter. Shader sind kleine Programme, geschrieben in einer C‐ähnlichen Syntax, die direkt auf dem Grafik‐ kartenprozessor ausgeführt werden. Dadurch kann ein Großteil der Berechnung von Grafik auf die darauf spezialisierte Grafikkarte ausgelagert werden. Heutzutage unterstützen fast alle Grafikkarten programmierbare Shader. Das XNA‐ Framework schreibt sogar eine Grafikkarte mit Shaderunterstützung vor. Da Blade3D auf dem XNA‐Framework aufbaut, müssen alle Objekte durch Shader gezeichnet werden. Die in älteren Grafikkarten implementierte sogenannte Fixed‐ Function‐Pipeline wird nicht mehr unterstützt.
4.2.
Einen Effekt erstellen
Um einen neuen Effekt zu Erstellen, klicke im Objektbrowser mit der rechten Maustaste auf den Ordner Effects und wähle New Effect. Ein neuer Effekt mit dem Namen Effect.fx wurde nun in dem Ordner erstellt. Mit einem Doppelklick auf den Effekt wird dieser im Effekteditor geladen. Es wird bereits standardmäßig ein recht umfangreicher HLSL‐Shader geladen, wie man im Effekteditor erkennen kann. Wir werden nun selber einen einfachen Shader schreiben und löschen dazu erstmal den gesamten Shadercode in der Effektdatei Effect.fx. Der Shader wird am Ende ein Objekt mit einer bestimmten Farbe und nicht schattiert zeichnen. Hierzu benötigen wir als erstes eine Variable, die die Farbe, in der das Objekt gezeichnet wird, angibt: // Static Constants float3 DiffuseColor : DiffuseMaterialColor = {1.0f, 0.0f, 0.0f};
Die Variable ist vom Typ float3 (also ein Vektor mit 3 Komponenten), heißt DiffuseColor, ist von der Semantik DiffuseMaterialColor und ist standardmäßig auf (1,0,0), also Rot (R,G,B) gestellt.
20
Semantiken bieten eine Verknüpfung von Parametern im Shaderquellcode mit der Blade3D‐ Oberfläche und internen Prozessen. So hat z.B. die Angabe der Farbe als DiffuseMaterialColor zur Folge, dass man im Material, das den Effekt nutzt diese Farbe über einen Farbwähler komfortabel einstellen kann. Für die Transformation der Vertizes des Objekts auf den Bildschirm benötigt man die sogenannte World View Projection‐Matrix, die Blade3D bereits fertig berechnet zur Verfügung stellt (sie wird aus der Kamerablickrichtung und den Kameraeinstellungen berechnet): // Dynamic Constants float4x4 WorldViewProjection
: WorldViewProjection;
Nun schreiben wir den Vertex‐Shader, der für jedes Vertize des Objektes ausgeführt wird. Vor dem Vertex‐Shader muss man noch die Ausgabe des Shaders festlegen. In unserem Fall reicht die Ausgabe der transformierten Position des Vertizes. Dazu legen wir eine Struktur mit einem Vektor mit 4 Komponenten (vom Typ float4) mit dem Namen Pos und der Semantik Position an. // Vertex Shader struct VS_OUTPUT { float4 Pos: Position; };
Der Vertex‐Shader bekommt als Eingabeparameter nur die Position des Vertize und soll eine Struktur vom Typ VS_OUTPUT zurückgeben, die wir gerade definiert haben. VS_OUTPUT VertexShader(float4 inPos: Position)
Im Vertex‐Shader werden wir nur eine Variable vom Typ VS_OUTPUT anlegen und der darin enthaltene Vektor wird das Ergebniss einer Multiplikation der eingegebenen Position (inPos) mit der anfangs definierten Matrix sein, d.h. die ursprüngliche Position des Vertizes wird auf den Bildschirm transformiert. Diese transformierte Position wird zurückgegeben. { VS_OUTPUT Out; Out.Pos = mul(inPos, WorldViewProjection); return Out; }
Nun brauchen wir noch den Pixel‐Shader, der für jedes Pixel, das am Ende vom Objekt auf dem Bildschirm erzeugt wird, durchlaufen wird. Der Pixel‐Shader kann auch Eingabeparameter haben aber dies ist in unserem einfachen Beispiel‐Shader nicht nötig. Der Pixelshader gibt immer einen 4‐ Komponenten‐Vektor zurück. Dieser bestimmt die Farbe (R,G,B) und als 4. Komponente den Alpha‐ Wert des Pixels, falls Alpha Blending aktiviert ist. Als Semantik wird hierfür COLOR0 verwendet. // Pixel Shader float4 PixelShader() : COLOR0
Der Pixel‐Shader gibt als Farbe, die nun auf dem Bildschirm gezeichnet wird nur die Farbvariable mit einem Alpha‐Wert von 1 zurück: { return float4(DiffuseColor, 1.0f);
21
}
Materialien benutzen immer eine bestimmte Technik eines Effektes und eine Technik kann aus 1 oder mehreren Passes bestehen. Ein Pass benutzt immer einen Vertex‐ und einen Pixel‐Shader und setzt gegebenenfalls sogenannte Render States wie z.B. Alpha Blending. Unser Effekt benötigt nur eine Technik mit einem Pass. Die Shader werden für ein bestimmtes Shader‐Profil kompiliert. In unserem Falle der Vertex‐Shader für 1.1 (vs_1_1) und der Pixel‐Shader für 2.0 (ps_2_0). // Technique technique t0 { pass p0 { VertexShader = compile vs_1_1 VertexShader(); PixelShader = compile ps_2_0 PixelShader(); } }
Somit ist der Effekt fertig und er sollte fehlerfrei kompilieren (wird automatisch oder explizit über Drücken von F12 gemacht).
4.3.
Ein Material erstellen
Nun muss man ein neues Material erzeugen, das den Effekt nutzt. Dazu klickt man mit der rechten Maustaste im Objektbrowser auf den Ordner Materials und wählt Create und klickt im nun aufklappenden Menü den soeben erstellten Effekt Effect.fx aus. Das nun erstellte Material ist im Materialordner sichtbar und heißt verwirrenderweise auch Effect.fx. Deshalb ist es ratsam es umzubenennen, z.B. in MeinMaterial. Man kann nun ein neues Objekt erzeugen und im zugehörigen Eigenschaften‐Inspektor in der Kategorie Material Info die Eigenschaft Material verändern und hier Mein Material einstellen. Sofort sieht man, wie das Objekt in roter Farbe im Szeneneditor gezeichnet wird. Außerdem erscheint unter der Eigenschaft Material sofort die neue Eigenschaft Diffuse Color, über die man die Farbe setzen kann, in der das Objekt gezeichnet werden soll. Die von uns erstellte Technik mit dem Namen t0 ist auch unter der Eigenschaft Technique zu sehen.
Abbildung 16 ‐ Der erstellte Effekt in Aktion
22
Kompletter Shadercode des Effektes: // Static Constants float3 DiffuseColor : DiffuseMaterialColor = {1.0f, 0.0f, 0.0f}; // Dynamic Constants float4x4 WorldViewProjection: WorldViewProjection; // Vertex shader struct VS_OUTPUT { float4 Pos: Position; }; VS_OUTPUT VertexShader(float4 inPos: Position) { VS_OUTPUT Out; Out.Pos = mul(inPos, WorldViewProjection); return Out; } // Pixel shader float4 PixelShader() : COLOR0 { return float4(DiffuseColor, 1.0f); } // Technique technique t0 { pass p0 { VertexShader = compile vs_1_1 VertexShader(); PixelShader = compile ps_2_0 PixelShader(); } }
23
5. Verhalten integrieren Blade3D ermöglicht die Implementation von Spiel‐Logik in einer visuellen Art und Weise durch Logik‐ Diagramme oder klassisch durch Skripte und Makros.
5.1.
LogikDiagramme
Mit Logik‐Diagrammen erstellt man intuitiv Spiel‐Logik durch Verknüpfen von bestimmten Eigenschaften der Blade3D‐Objekte. Um ein Diagramm zu erstellen, klickt man mit der rechten Maustaste im Objektbrowser auf den Ordner Graphs und wählt Create/Logic Diagramm. Im Szeneneditor sieht man das Diagramm‐Fenster halbtransparent vor der eigentlichen Szene. In diesem Fenster werden die einzelnen Objekte angeordnet und miteinander verbunden. Man kann durch gedrückt halten der linken Maustaste die Ansicht des Diagramms verschieben und mit dem Mausrad raus‐ und reinzoomen. Man kann die Größe des Fensters ändern indem man auf eine Ecke des weißen Randes linksklickt, die Maustaste gedrückt hält und die Maus bewegt. Das Fenster ist nur sichtbar, wenn das Logik‐Diagramm im Objektbrowser ausgewählt ist. Will man das Diagramm also ausblenden, so genügt es ein anderes Objekt auszuwählen. Um auf ein Objekt in einem Diagramm zuzugreifen zieht man es einfach bei gedrückter linker Maustaste vom Objektbrowser in das Diagramm‐Fenster. Man sieht nun das Objekt mit seinen Eigenschaften im Diagramm. Jede Eigenschaft hat dabei einen Eingang auf der linken und einen Ausgang auf der rechten Seite. Man kann somit jede Eigenschaft eines Objektes durch eine andere Eigenschaft eines anderen Objektes durch Verknüpfen der Ein‐ und Ausgänge steuern.
Abbildung 17 ‐ Das Standard‐Kamerasteuerungs‐Diagramm
Will man 2 Eigenschaften verknüpfen, so zieht man mit gedrückt gehaltener linker Maustaste vom Ausgang des einen Objektes zum Eingang des anderen Objektes. Ein Pfeil verbindet nun die beiden
24
Eigenschaften. Beim Ziehen der Verbindung blinken alle Eingänge die denselben Datentyp verwenden grün und alle Eingänge die einen Typ verwenden in den der Ausgangstyp konvertiert werden kann blinken orange. Man kann also nur Eigenschaften verbinden die denselben oder einen konvertierbaren Typ enthalten. Eine bereits bestehende Verbindung ist durch einen orangenen Pfeil gekennzeichnet. Man kann die Objekte frei positionieren, indem man sie bei gedrückt gehaltener linker Maustaste verschiebt. Die Verbindungen bleiben dabei erhalten. Um eine Verbindung zu löschen, klickt man mit der rechten Maustaste auf sie und wählt Delete Connection. Logik‐Diagramme sind immer aktiv, d.h. sie werden einmal pro Frame ausgeführt.
5.2.
Skripte
Skripte werden bei bestimmten Ereignissen, wie z.B. Mausklicks, Tastendrücken oder wenn sich eine Eigenschaft eines Objektes ändert, ausgeführt. Skripte sind immer an bestimmte Objekte gebunden. Sie werden in einer C#‐ähnlichen Syntax geschrieben. Um ein Skript zu erzeugen, klickt man mit der rechten Maustaste auf ein Objekt im Objektbrowser und wählt Add Script. Danach öffnet sich ein Fenster, indem man auswählt, bei welchem Ereignis das Skript ausgewählt wird. Unter der Kategorie Events findet man die gängigen Ereignisse wie OnUpdate und OnMouseClick usw. und in den restlichen Kategorien kann man eine Eigenschaft des Objektes auswählen. Wählt man eine Eigenschaft, so wird das Skript immer ausgeführt, wenn sich diese Eigenschaft ändert. Nach Klicken auf Ok wird das Skript als ein grüner Kreis im Objektbrowser unter dem Objekt angezeigt. Klickt man auf das Skript im Objektbrowser, so öffnet sich der Skripteditor und lädt das Skript. Standardmäßig ist ein erstelltes Skript nicht leer, sondern enthält eine Anweisung, die beim Auslösen des Skripts eine kurze Textnachricht in das Ausgabefenster schreibt. So kann man immer im Ausgabefenster sehen (das Ausgabefenster öffnet sich, wenn man unterhalb des Skripteditors auf Output klickt), wann das Skript ausgeführt wurde. Im Skripteditor kann man nun das Skript auf der rechten Seite eingeben oder zu einem anderen Skript durch Klicken auf den zugehörigen Namen in der linken Liste wechseln. Die Skripte werden durch Drücken von F12 oder wenn man den Skript‐Editor schließt, kompiliert.
5.3.
Makros
Für kleine und häufig vorkommende Aufgaben, wie Eigenschaften auf einen bestimmten Wert zurücksetzen, Eigenschaften auf zufällige Werte setzen oder Sounds und Animationen abzuspielen, bieten sich Makros an. Um ein Makro zu erstellen, klickt man mit der rechten Maustaste auf den Ordner Macros im Objektbrowser und wählt Create und einen Makro‐Typ. Der Typ Set Value Macro setzt eine Eigenschaft
25
eines Objektes auf einen bestimmten Wert. Man gibt im Objektbrowser des Makros unter Target Instance das Objekt und unter Target Property die zu setzende Eigenschaft des Objektes an. Unter Time kann man eine Zeitverzögerung angeben und unter Interpolate kann man die Interpolation hin zum Zielwert aktivieren. Unter dieser Eigenschaft stellt man den Wert ein, auf den die Objekteigenschaft beim Aktiviren des Makros gesetzt oder interpoliert werden soll. Man kann ein Makro aktivieren, indem man in der Kategorie Macro unter der Eigenschaft Active auf den Button klickt oder indem man diese Eigenschaft in einem Skript auf true setzt. Nach Ausführen des Makros wird die Active‐Eigenschaft wieder auf false gesetzt. Die Makro‐Typen Sound und Animation spielen einen Sound oder eine Animation eines Modells ab. Der Typ Compound Macro ist eigentlich kein eigenständiges Makro. Man kann andere Makros innerhalb eines Compound Macros erzeugen (durch Rechtsklicken auf das Makro und wählen von Create und dem Makro‐Typ). Wird nun das übergeordnete Compound Macro aktiviert, so werden auch alle anderen enthaltenen Makros aktiviert. Einem Random Macro kann man ähnlich dem Compound Macro Makros unterordnen. Beim Aktivieren des Random Macros wird dann zufällig ein untergeordnetes Makro aktiviert.
26
6. Soundsystem Blade3D enthält ein einfaches Soundsystem. Man kann Sounds der Szene hinzufügen, sie mit Effekten versehen und bei bestimmten Ereignissen auslösen.
6.1.
Samples und Sounds erstellen
Um ein Sample, also eine Sounddatei in dem Format .wav (die Formate .ogg, .mp3, .mod, .it, .s3d und .xm sollen später noch unterstützt werden) zu laden, klicke mit der rechten Maustaste im Objektbrowser auf den Ordner Audio/Samples, klicke dann auf Import Samples und wähle im darauffolgenden Datei‐Dialog eine Sound‐Datei aus. Die Datei befindet sich nun im Ordner Samples. Per Doppelklick wird die Datei einmal abgespielt (jedoch maximal 20 Sekunden lang). Will man die Datei in voller Länge hören, so muss man darauf rechtsklicken und im Menü Preview wählen. Jetzt kann man einen Sound erstellen, der dieses Sample nutzt. Das Verhältnis zwischen Samples und Sounds ist ähnlich dem zwischen Effekten und Materialien. Mehrere Sounds können ein Sample nutzen aber mit unterschied‐ lichen Einstellungen und Effekten abspielen. Um den Sound zu erstellen klickt man rechts auf den Ordner Audio/Sounds im Objektbrowser und wählt Create/Sound. Öffne nun den Eigenschaften‐Inspektor des eben erzeugten Sounds mit Rechtsklick darauf und Abbildung 18 ‐ Soundeigenschaften Open Property Sheet. Wähle in der Eigenschaft Sample das zuvor erstellte Sample aus. Hinweis: Alternativ kann man auch einfach das erstellte Sample bei gedrückter linker Maustaste in den Sounds‐Ordner ziehen. Ein Sound hat die Eigenschaften Sample, Volume (Lautstärke), Max Duration (maximale Abspiellänge, standardmäßig auf ‐1 für Abspielen in voller Länge gesetzt) und Loop (ob der Sound in Endlosschleife gespielt werden soll). Um dem Sound einen Effekt hinzuzufügen, klicke rechts auf den Sound im Objektbrowser und wähle Create und den gewünschten Effekt. Es gibt Effekte wie z.B. Echo (ein kurzer Hall), Reverb (Hall), Compressor (Dynamik‐Kompressor), Distortion (Verzerrung) oder Parametric EQ (parametrischer Equalizer). Jeder Effekt bietet dabei weitgehende Einstell‐ möglichkeiten (siehe die Blade3D‐Wikipedia). Es können einem Sound beliebig viele Effekte zugewiesen werden.
Abbildung 19 ‐ Einstellmöglichkeiten des Echo‐Effekts
Samples und Sounds können in Containern verwaltet werden. Diese entsprechen Unterordnern im jeweiligen Samples‐ oder Sound‐Ordner. Einen Sample‐Container erzeugt man durch einen Rechtsklick auf den
27
Samples‐Ordner und Create/Sample Container. Einen Sound‐Container erzeugt man durch einen Rechtsklick auf den Sounds‐Ordner und Create/Sound Container/Sound Container. Als Spezialfall kann man hier alternativ auch einen Random Sound Container über Create/Sound Container/Random Sound Container. Die in diesem Ordner enthaltenen Sounds können zufällig abgespielt werden.
6.2.
Sounds in der Szene verwenden
Sounds können durch Sound‐Trigger oder durch Skripte abgespielt werden. 6.2.1. SoundTrigger Ein Sound‐Trigger spielt einen Sound ab, wenn die Kamera einen bestimmten Bereich betritt oder wieder verlässt. Um einen Sound‐Trigger zur Szene hinzuzufügen klickt man mit der rechten Maustaste auf den Scene‐Ordner im Objektbrowser und wählt Create/Trigger Volume/Sound Trigger/Sound Trigger. Man sieht nun den Bereich des Triggers im Szeneneditor durch einen roten Quader gekennzeichnet. Diesen kann man nun ganz normal positionieren, rotieren und skalieren. Achtung: Man muss den Trigger immer im Objektbrowser auswählen, da er im Szeneneditor unsichtbar ist, wenn er nicht selektiert ist.
Abbildung 20 ‐ Sound Trigger‐Hüllquader und Eigenschaften
Im Eigenschaften‐Inspektor des Triggers stellt man den Sound ein, der beim Betreten (Enter Sound) und beim Verlassen (Leave Sound) abgespielt werden soll. Die Eigenschaft Kill Sound OnExit bestimmt, ob der Enter Sound gestoppt werden soll, wenn der Bereich verlassen wird. Man kann statt eines bestimmten Sounds auch einen Random Sound Container angeben. Dann wird immer zufällig ein Sound aus dem Container ausgewählt. 6.2.2. SoundSkript Hier folgt ein kleines Beispiel, wie man einen Sound mithilfe eines Skriptes abspielt. Füge der Szene ein Objekt, wie z.B. eine Kugel, hinzu. Klicke im Objektbrowser auf die Kugel mit der rechten Maustaste und wähle Add Script. Wähle im nun folgenden Dialog das Mouse Down‐Ereignis. Wähle im Skripteditor das eben erstellte OnMouseDown‐Skript aus. Füge dem Skript folgende Anweisungen hinzu: IObject sounds = context.Site.GetObject("#Module/Audio/Sounds"); IBlade3DSound sound = (IBlade3DSound) sounds.GetChild(0).Extension; sound.Play();
28
Drücke F12 zum Kompilieren des Skripts. Beim Klicken auf die Kugel wird nun der Sound abgespielt. In der ersten Zeile wird eine Referenz auf alle Sound‐Objekte in dem angegebenen Verzeichnis erstellt. In der zweiten Zeile wird aus diesen Sound‐Objekten das erste ausgewählt und in der dritten Zeile abgespielt.
29
7. Blade3DFunktionalität erweitern In diesem Abschnitt wird gezeigt, wie man mit Visual C# Express 2005 einen Operator schreibt, der in die Blade3D‐IDE eingebunden wird und den man in Logikdiagrammen nutzen kann. Der Operator soll den Absolutwert einer Zahl berechnen. Man erstellt in C# Express ein neues Class Library‐Projekt. Man löscht den Quellcode der bereits erzeugten Klasse. Zuerst benötigt man den Standardnamensraum System sowie den Blade3D‐ Namensraum. using System; using Blade3D.Runtime.Extensibility;
Dann kommt der Namensraum, indem die nachfolgenden Klassen definiert werden, z.B. OperatorTutorial. Außerdem definiert man eine Klasse in der die als statische Funktionen realisierten Operatoren enthalten sind. namespace OperatorTutorial { [OperatorGroup(Description = "Meine neuen Operatoren")] public class MeineOperatoren {
Die Zeile in eckigen Klammern über dem Klassennamen ist ein Attribut, das weitere Informationen zur Klasse enthält, die zur Laufzeit abgerufen werden können. In diesem Fall ist die Klasse eine Gruppe von Operatoren (OperatorGroup) mit einer Beschreibung, die später in Blade3D direkt in der Umgebung angezeigt wird. Als nächstes folgt eine statische Methode zur Berechnung des Absolutwertes einer Gleitkommazahl. [Operator(Description = "Berechnet den Absolutwert eines Floats")] public static void Abs( [OperatorParameter(Description = "Wert.", DefaultValue = "0")] float wert, [OperatorParameter(Description = "Ergebnis.")] out float ergebnis )
Die Funktion heißt Abs und ist durch das Attribut als Operator gekennzeichnet. Die Funktionen hat einen Ein‐ (wert) und einen Ausgabeparameter (ergebnis). Diese Parameter sind als solche durch das Attribut OperatorParameter gekennzeichnet. Der eigentliche Methodenquellcode folgt nun: { ergebnis = Math.Abs(wert); }
Man kann nun in dieser Operatoren‐Gruppe weitere Operatoren definieren wie z.B. die Berechnung des Absolutwertes einer Ganzzahl: [Operator(Description = "Berechnet den Absolutwert eines Ints")] public static void IAbs( [OperatorParameter(Description = "Wert.", DefaultValue = "0")] int wert, [OperatorParameter(Description = "Ergebnis.")]
30
out int ergebnis ) { ergebnis = Math.Abs(wert); }
Die Klasse und der Namensraum müssen noch geschlossen werden. } }
Das Projekt kann nun kompiliert werden und es wird im Projektverzeichnis eine .dll‐Datei erzeugt. Diese muss nun nur noch in das Blade3D‐Installa‐ tionsverzeichnis kopiert werden (standardmäßig Programme/Digini/Blade3D/). Blade3D muss erst neu gestartet werden bevor der Operator zur Abbildung 21 ‐ Die Operatoren im Auswahlmenü Verfügung steht. Um den Operator einem Logikdiagramm hinzuzufügen, klickt man darin mit der rechten Maustaste und wählt Create. In der aufklappenden Liste findet sich der Punkt Meine Operatoren, indem die beiden erstellten Operatoren zu finden sind. Man kann den Operator nun in einem Logik‐Diagramm nutzen.
Abbildung 22 ‐ Der Operator im Logik‐Diagramm
31
8. OnlineHilfe Die Online‐Hilfe ist jederzeit durch Drücken von F1 erreichbar. Je nachdem welcher Bereich gerade aktiv ist oder welches Objekt gerade ausgewählt ist, wird kontextsensitiv die entsprechende Seite in der Dokumentation angezeigt. Ist gerade ein Objekt aktiv, so wird eine kurze Erklärung des Objektes sowiel alle seine Eigenschaften und von welchen Basis‐Klassen es abgeleitet ist, angezeigt. Viele Objekte enthalten außerdem eine kurze Einführung wie man sie erstellt und auch verwendet. Über den Help Home‐Button in der Hilfe‐Werkzeugleiste kommt man zur Startseite der Online‐Hilfe. Hier findet man eine Schnelleinführung in die Bedienung von Blade3D (Quick Start), Tutorials, Beispiele (Samples) und freie Texturen und Modelle. Die Samples lassen sich durch Klicken auf das Sample‐Bildchen direkt runterladen und installieren. Das Sample ist nach dem Herunterladen bereits fertig in Blade3D geladen. Video‐Tutorials können auch direkt im Hilfe‐Fenster angeschaut werden. So kann man gleich selber die Schritte des Tutorials nachvollziehen.
Abbildung 23 ‐ Die Startseite der Online‐Hilfe in der Blade3D‐Umgebung
Desweiteren gibt es noch eine sehr schnell wachsende Wiki zu Blade3D. Diese ist unter http://wiki.blade3d.com zu erreichen.
32
9. Tutorial: PongSpiel Im diesem Abschnitt wird gezeigt, wie man Blade3D in der Praxis einsetzt. Dies wird durch die Erstellung eines einfachen Pong‐Spiels gezeigt. In dem Spiel muss man versuchen eine Kugel durch Steuerung von 2 Schlägern auf dem Spielbrett zu halten. Zu Beginn erstellt man ein neues Modul über das Dateimenü und Klicken auf New Module. Wichtig: Speichere das Modul von Zeit zu Zeit ab.
9.1.
Das Spielbrett
Als erstes erzeugt man eine neue Klasse, um das Spielbrett zu repräsentieren. Rechtsklicke auf den Ordner Types im Objektbrowser und wähle Add Type. Gib den Namen PongBoard und wähle No Base Type unter Categories. Nun sieht man den Pong Board‐Typ unter Types im Objektbrowser. Um der Klasse eine neue Eigenschaft hinzuzufügen, in diesem Falle eine Gleitkommazahl, klicke rechts auf Pong Board und wähle Create/Property/Single. Ändere den Namen der Eigenschaft auf Breite. Doppelklicke auf die Eigenschaft, um den Eigenschaften‐Inspektor zu öffnen. Ändere die Werte wie in Abbildung 25 gezeigt. Abbildung 24 ‐ Erstellen einer neuen Klasse
Um diese Eigenschaft leicht verändern zu könnnen, ändert man unter der Kategorie Property die Eigenschaft In Place Editor in slider.
Man kann nun von der Board‐Klasse eine Instanz erzeugen, indem man auf den Ordner Instances rechtsklickt und Create/Pong Board wählt. Wenn man auf die Instanz doppelklickt, sieht man die Abbildung 25 ‐ Eigenschaft Breite Breite‐Eigenschaft auf einem Wert von 15.4 und einem Slider für den Bereich 1 bis 100 so wie man es vorher in der Klasse eingestellt hat. Wenn man die Klasse verändert, so werden alle Änderungen von den Instanzen der Klasse übernommen. Rechtsklicke auf die Breite‐Eigenschaft der Board‐Klasse und wähle Duplicate. Dies dupliziert die Eigenschaft. Ändere den Namen auf Höhe. Öffne den Eigenschaften‐Inspektor und ändere Default Value auf 12. Die restlichen Eigenschaften wurden bereits von Breite übernommen.
33
Öffnet man den Eigenschaften‐Inspektor der Instanz des Boards so sieht man die eben zur Klasse hinzugefügte Eigenschaft Höhe mit dem Wert 12. Man fügt der Szene nun ein Grid‐Objekt hinzu, um das Board zu repräsentieren. Dazu klickt man auf das Grid‐Icon in der Scene‐Werkzeugleiste. Jetzt sieht man ein Rechteck in der Mitte der Szene im Szeneneditor. Ändere den Namen des Grids in PongBoardGrid. Öffne dessen Eigenschaften und setze beiden Subdivision‐Eigenschaften auf 1. Ändere IsSelectable auf false in der Spatial‐Kategorie. Nun verbindet man das Grid mit der Board‐Klasseninstanz, damit das Grid die Eigenschaften der Instanz erbt. Dazu erzeugt man ein neues Logik‐Diagramm durch Rechtsklicken auf den Ordner Graphs und wählen von Create/Logic Diagramm. Ändere den Namen des Diagramms in PongBoardSetup. Öffne das Diagramm durch Anwählen des erzeugten Diagramms im Objektbroswer. Ziehe nun bei gedrückt gehaltener Maustaste die Board‐Instanz in das Diagramm. Jetzt sieht man die Board‐Instanz als Rechteck im Diagramm. Dabei sind die beiden Eigenschaften Breite und Höhe mit jeweils einem Ein‐ und einem Ausgang zu sehen. Schiebe die Board‐Instanz auf die linke Seite des Diagramms. Ziehe nun das Game Board Grid in das Diagramm und platziere es auf der rechten Seite. Ziehe einen Pfeil vom Ausgang der Breite‐Eigenschaft der Board‐Instanz zum Eingang der Length U‐Eigenschaft des Game Board Grids. Führe denselben Schritt für die Höhe durch und verbinde sie mit Length V. Das Grid übernimmt nun sofort die Eigenschaften für Höhe und Breite von der Board‐Instanz.
Abbildung 26 ‐ Die Kamera schaut nun auf das Board
34
Nun ändert man die Szeneneigenschaften, sodass man direkt von oben auf das Board schaut. Doppelklicke auf den Scene‐Ordner zum Anzeigen der Szeneneigenschaften. In der Kategorie ViewportBase ändere DrawFloor auf false. Dies versteckt das standardmäßig angezeigte Bodengitter. Doppelklicke auf das Camera‐Objekt im Objektbrowser unter Scene. Setze die Local Position auf 0, 10, 0 und die Local Rotation auf 0, 0, ‐90 wie in Abbildung 26. Jetzt erstellt man ein Material für das Board. Materialien sind Instanzen von Effekten. Erzeuge ein neues Material durch Rechtsklicken auf den Materials‐Ordner und Wählen von Create/Basic/GUI.fx. Dies ist ein einfacher Effekt. Er benutzt eine Textur und eine optionale Angabe zur Durchsichtigkeit (Opacity). Man sieht nun ein neues Material mit dem Namen GUI.fx. Ändere den Namen des Materials in GameBoardMaterial. Öffne die Eigenschaften des Game Board Grids. Stelle Material Info‐Kategorie unter Material das eben erzeugte Material ein. Daraufhin ändern sich die Einstellmöglichkeiten unter dem Materialnamen und man kann eine Textur für das Board auswählen, z.B. MarbleTile.vtf unter MyModule/Textures/Samples. Nun wird die Kamerasteuerung deaktiviert. Öffne dazu die Kamera‐Eigenschaften. Klicke unter der Active Rigid Body‐Kategorie bei der Eigenschafte Force Controller auf den kleinen blauen Kreis links, um die Eigenschaft auf zu setzen.
9.2.
Schläger erstellen
Nun werden 2 Schläger erstellt. Diese werden wieder als Grid dargestellt. Füge ein weiteres Grid der Szene hinzu. Ändere den Namen in LinkerSchläger und öffne die Eigenschaften des Grids. Setze beide Subdivision‐Eigenschaften auf 1. Setze Length U auf 0.5 und Length V auf 2.5. Setze die Local Position auf ‐7, 0.01, 0. Nun fügt man dem Schläger noch ein Material zu. Dazu erzeugt man ein neues Material durch Rechtsklicken auf den Materials‐ Ordner und Wählen von Create/Basic/Text.fx. Benenne das Material mit SchlägerMaterial. Weise dem linken Schläger das Material zu. In der MaterialInfo‐Kategorie der Schläger‐Eigenschaften mache folgende Einstellungen: setze UVScale auf 0.5 und 2.5, ändere Use Vertex Color auf false, um die Textur sichtbar zu machen, wähle eine Textur aus, z.B. Stone.vtf unter MyModule/Textures/ Samples.
35
Erzeuge von dem Schläger eine Kopie durch Rechtsklicken auf den Schläger im Objektbrowser und Wählen von Duplicate. Ändere den Namen des neu erzeugten Schlägers auf RechterSchläger und öffne seinen Eigenschaften‐Inspektor. Setze die Eigenschaften UVScale, Use Vertex Color und Diffuse Texture genauso wie beim linken Schläger. Setze die lokale Position auf 7, 0.01, 0. Damit wird der Schläger an den rechten Rand des Brettes verschoben.
Abbildung 27 ‐ Die PongGame‐Klasse
Nun erstellt man eine neue Klasse, die die Spiel‐Logik beinhalten soll und klickt dazu mit der rechten Maustaste auf Types im Objektbrowser und wählt Add Type. Nenne im erscheinenden Dialog diese neue Klasse PongGame. Doppelklicke auf die Scenes‐Kategorie auf der linken Seite und wähle auf der rechten Seite None als base type und schließe den Dialog mit OK ab. Dieser Basistyp stellt bereits eine Update‐Funktion zur Verfügung, in der die eigentliche Spiel‐ Logik einmal pro Frame ausgeführt wird. Nun werden der neuen Klasse einige Eigenschaften hinzugefügt die zur Steuerung der Schläger benötigt werden. Füge der PongGame‐Klasse eine Eigenschaft durch Rechtsklicken darauf und wählen von Create/Property/Vector3 zu. Nenne diese Eigenschaft LinkerSchlägerPosition. Setze in der Eigenschaft die Werte wie in Abbildung 28 und setze die Eigenschaft In Place Editor auf slider. Erstelle eine Instanz der eben erzeugten Klasse durch Rechtsklicken auf den Scene‐Ordner und wähle Create/Scene Items/Pong Game. In Abbildung 28
36
den Eigenschaften der Klassen‐ Instanz im Scene‐ Ordner sieht man die Werte der Schlägerposition. Diese kann man nun in einem Logik‐Diagramm mit der wirklichen Abbildung 30 ‐ Diagramm Schläger Position Link Position des Schlägers verbinden. Dazu erstellt man ein neues Logik‐ Diagramm und nennt es SchlägerPositionLink. In das geöffnete Diagramm zieht man die PongGame‐Instanz und posiert sie auf der linken Seite. Danach zieht man den linken Schläger in das Diagramm und platziert ihn in der Mitte. Verbinde nun die beiden Positionseigenschaften wie in Abbildung 30. Wenn man nun die Eigenschaft Linker Schläger Position in der Klasseninstanz ändert, so ändert sich auch die Position des Schlägers auf dem Spielbrett. Dupliziere die Linker Schläger Position‐Eigenschaft und nenne sie RechterSchlägerPosition. Gib die Werte wie in Abbildung 29 ein. Ziehe den rechten Schläger in das Logik‐Diagramm und platziere ihn rechts neben dem linken Schläger. Verbinde die Rechter Schläger Position‐ Eigenschaft mit der Local Position des rechten Schlägers. Nun werden die Positionen der Schläger Abbildung 29 durch die Klasse gesteuert. Die Schlägergrößen sollen auch von der Klasse gesteuert werden. Dazu erzeugt man in der PongGame‐Klasse im Ordner Types eine neue Eigenschaft Create/Property/Single. Nenne diese Eigenschaft SchlägerBreite. Setze die Werte der Eigenschaft auf 0.5, 0.3, 1, 0.1 Abbildung 31 und wähle als In Place Editor wieder slider. Dupliziere die Eigenschaft und nenne die Kopie SchlägerHöhe und setze die Eigenschaften auf 2.5, 0.5, 10, 0.1. Verbinde nun in dem Schläger Position Link‐Diagramm die Eigenschaften Schläger Breite und Schläger Höhe mit den Eigenschaften LengthU und LengthV der beiden Schläger wie in Abbildung 32.
Abbildung 32
37
Jetzt wird auch die Schlägergröße über die Klasse gesteuert. Dies wird bei der Kollisionserkennung später noch nützlich sein.
9.3.
Schläger bewegen
Der Einfachheit wegen werden wir nur eine Ein‐Spieler‐Steuerung einbauen, d.h. wenn ein Schläger nach oben bewegt, so bewegt sich der andere nach unten. Erzeuge ein neues Logik‐Diagramm mit dem Namen SchlägerKontrolle. Ziehe die PongGame‐Instanz in das Diagramm. Klicke in den Hintergrund des Diagramms. Dann klicke mit der rechten Maustaste und wähle Create/Input Operations/Combined Control Adapter. Dies ist der Eingabe‐Operator, der standardmäßig die Kamera steuert, d.h. er nimmt Eingaben der Tastatur, der Maus und des Xbox 360 Controllers entgegen. Füge einen weiteren Operator über Create/Vector 2 Operators/Vector 2 To Parts. Dieser Operator extrahiert die Y‐Komponente aus dem Ausgang Linear Thrust des Controllers. Verbinde den Linear Thrust‐Ausgang mit dem DecomposeVector2‐Operator‐Eingang. Außerdem werden die Werte der linken Schlägerposition benötigt. Man erzeugt dazu den Operator Create/Vector3 Operators/Vector3 To Parts und verbindet diesen mit dem Ausgang Eigenschaft Linker Schläger Position. Die Position wird durch Tastatureingaben verändert und wieder an die Klasseninstanz zurückgegeben. Erzeuge den Operator Create/Math/Add Floats und platziere ihn rechts vom DecomposeVector3‐ Operator. Verbinde den Z‐Ausgang des DecomposeVector3‐Operators mit dem A‐Eingang des Add Floats‐Operators. Verbinde den Y‐Ausgang des DecomposeVector2‐Operators mit dem B‐Eingang des Add Floats‐Operators. Erzeuge einen ComposeVector3‐Operator (also einen Vector3 from Parts‐ Operator, die beiden Bezeichnungen stehen für denselben Operator). Verbinde den Ausgang des Add
Abbildung 33
38
Floats‐Operators mit dem Z‐Eingang des neuen ComposeVector3‐Operators. Verbinde nun die die X‐ und Y‐Ausgänge des DecomposeVector3‐Operators mit den jeweiligen Eingängen des ComposeVector3‐Operators. Abbildung 33 zeigt das Diagramm. In dem Diagramm nehmen wir uns die Z‐Position (also der Schläger bewegt sich auf und ab), addieren einen Wert abhängig von einer Tastatureingabe und bilden daraus die resultierende Position. Nun muss der Wert der Position nur noch zurückgeschrieben werden. Dazu zieht man noch einmal die PongGame‐Instanz in das Diagramm und positioniert sie auf der rechten Seite. Man verbindet den Ausgang des ComposeVector3‐Operators mit dem Eingang der Eigenschaft Linker Schläger Position der 2. PongGame‐Instanz im Diagramm. Nun muss das selbe Verfahren auf den rechten Schläger angewendet werden. Nur der Wert der in Abhängigkeit der Tasteneingabe addiert wird muss negiert werden, damit sich der Schläger in die entgegengesetzte Richtung bewegt. Erzeuge im selben Diagramm den Operator Vector2 Operators/Negate Vector2. Verbinde den Linear Thrust‐Ausgang mit dem Eingang des Negate Vector2‐Operators und platziere diesen unterhalb des Decompose Vector2‐Operators. Füge einen weiteren Decompose Vector2‐Operator hinzu (über Vector2 Operators/Vector2 To Parts). Verbinde den Ausgang des Negate‐Operators mit dem Eingang des neuen Decompose‐Operators und positioniere ihn rechts des ersten Decompose Vector2‐Operators. Erzeuge nun eine Decompose Vector3‐Operator und platziere ihn unterhalb des anderen. Verbinde den Ausgang der rechten Schlägerposition mit dem Eingang des zweiten Decompose Vector3‐Operators. Erzeuge einen zweiten Compose Vector3‐Operator und platziere ihn unterhalb des ersten. Verbinde die X‐ und Y‐Ausgänge des zweiten Decompose Vector3‐Operators mit den jeweiligen Eingängen des zweiten Compose Vector3‐Operators. Erzeuge einen weiteren Add Floats‐Operator und platziere ihn unter dem ersten. Verbinde den Z‐Ausgang des zweiten Decompose Vector3‐Operators mit dem A‐Eingang des zweiten Add Floats‐Operators. Verbinde den Y‐Ausgang des zweiten Decompose Vector2‐Operators mit dem
Abbildung 34
39
B‐Eingang des zweiten Add‐Floats‐Operators. Verbinde den Ausgang des zweiten Add Floats‐ Operators mit dem Z‐Eingang des zweiten Compose Vector3‐Operators. Verbinde zum Schluss den Ausgang des zweiten Compose Vector3‐Operators mit Eingang der Eigenschaft Rechter Schläger Position der zweiten PongGame‐Instanz. Das Ergebniss ist in Abbildung 34 zu sehen. Jetzt werden die Positionen der beiden Schläger durch Drücken der Tasten W und S oder druch Hoch und Runter auf dem Xbox‐Controller verändert. Die Bewegung der Schläger ist noch zu empfindlich und deswegen werden wir noch einen Geschwindigkeits‐Faktor in das Diagramm einfügen. Setze vorher die Positionen der Schläger durch einen Klick auf den kleinen Kreis im Eigenschaften‐Inspektor der PongGame‐Instanz links neben zurück auf den Standardwert (siehe Abbildung 35).
Abbildung 35
Füge der PongGame‐Klasse (im Ordner Types) eine neue Eigenschaft (Gleitkommazahl) über Create/Property/Single hinzu und nenne sie SchlägerGeschwindigkeit. Setze die Werte der Eigenschaft auf 0.25, 0.01, 10, 0.05 und gib bei In Place Editor slider ein. Man benutzt nun diese Eigenschaft, um die Tastatureingabe im Schläger Kontrolle‐ Diagramm zu skalieren. Öffne nun dieses Diagramm und rechtsklicke nacheinander auf die beiden Verbindungen, die von Linear Thrust ausgehen und wähle Delete Connection, um die Verbindungen zu löschen. Füge einen neuen Operator unter Create/Vector2 Operators/Vector2 Multiply ein, der 2 Vektoren multipliziert. Verbinde Linear Thrust von dem Combined Control Adapter mit dem Eingang Vector A des eben erzeugten Operators. Verbinde den Ausgang des Multiply‐Operators mit den Eingängen der Decompose Vector2‐ und Negate Vector2‐Operatoren, die zuvor mit Linear Thrust verbunden waren. Nun benötigt man nur noch einen weiteren Vector2 mit dem der andere Vektor skaliert wird. Dieser neue Vektor wir mithilfe der SchlägerGeschwindigkeit‐Eigenschaft erzeugt. Erzeuge dazu einen weiteren Operator über Create/Vector2 Operators/Vector2 From Parts. Verbinde diese Eigenschaft von PongGame mit dem Y‐Eingang des neuen Compose Vector2‐Operators. Verbinde den Ausgang dieses Operators mit dem Eingang Vector B des Multiply Vector2‐Operators (siehe Abbildung 36). Jetzt ist die Bewegung der Schläger deutlich langsamer und besser steuerbar als vorher. Man kann die Geschwindkeit über die neue Eigenschaft Schläger Geschwindigkeit nach belieben anpassen. Bisher verlassen die Schläger aber den Bildschirm, wenn man sie zu weit bewegt. Man limitiert nun den Bewegungsbereich mithilfe des Update‐Skripts, das anfangs des Abschnitts bereits kurz erwähnt wurde. Rechtsklicke auf die PongGame‐Klasse und wähle Add Script und dann Update in der erscheinenden Liste. Es erscheint ein neuer Eintrag unter der Klasse mit eine grünen Kreis und dem Namen OnUpdate. Das ist das neu erzeugte Skript‐Ereigniss. Mit einem Linksklick darauf, wird es im Skripteditor geöffnet.
40
Abbildung 36 ‐ Das Schläger Kontrolle‐Diagramm
Die erste Zeile in dem Skript, gibt immer wenn das Skript aktiviert wird die in Klammern angegebene Zeichenkette im Ausgabefenster aus. Bisher passiert jedoch noch nichts, weil das Skript noch nicht aktiviert wurde. Um dies zu erreichen, öffne die Eigenschaften der PongGame‐Instanz im Scene‐ Ordner und gehe in die Kategorie Spatial. Setze die Eigenschaft Fire Update auf true. Jetzt wird die das Skript mit jedem Frame ausgeführt und das Ausgabefenster füllt sich mit den Ausgaben des Skriptes. Lösche die erste Zeile des Skriptes, da diese für die Logik nicht notwendig ist. Speichere die Schlägerpositionen und die Schlägerhöhe in Variablen ab: Vector3 linkerSchlaegerPosition = (Vector3)context.Site["LinkerSchlägerPosition"]; Vector3 rechterSchlaegerPosition = (Vector3)context.Site["RechterSchlägerPosition"]; float schlaegerHoehe = (float)context.Site["SchlägerHöhe"];
Folgende Werte soll die Schlägerposition nie überschreiten: float maxSchlaegerZ = 7.0f; float minSchlaegerZ = -7.0f;
Überschreitet die Schlägerpositionen die festgelegten Werte, so wird die Position auf die Maximalposition in Abhängigkeit zur Schlägerhöhe gesetzt: if ((linkerSchlaegerPosition.Z + schlaegerHoehe) > maxSchlaegerZ) { linkerSchlaegerPosition.Z = maxSchlaegerZ - schlaegerHoehe;
41
} else if ((linkerSchlaegerPosition.Z - schlaegerHoehe) < minSchlaegerZ) { linkerSchlaegerPosition.Z = minSchlaegerZ + schlaegerHoehe; } if ((rechterSchlaegerPosition.Z + schlaegerHoehe) > maxSchlaegerZ) { rechterSchlaegerPosition.Z = maxSchlaegerZ - schlaegerHoehe; } else if ((rechterSchlaegerPosition.Z - schlaegerHoehe) < minSchlaegerZ) { rechterSchlaegerPosition.Z = minSchlaegerZ + schlaegerHoehe; }
Schließlich werden die Positionen zurückgeschrieben: context.Site["LinkerSchlägerPosition"] = linkerSchlaegerPosition; context.Site["RechterSchlägerPosition"] = rechterSchlaegerPosition;
Drücke F12 zum Kompilieren des Skripts. Wenn man nun die Schläger bewegt so stoppen sie am Spielbrettrand. Damit ist das Spielbrett und die Schläger fertig.
9.4.
Ball erstellen
Der Ball wird ähnlich den Schlägern funktionieren. Er hat eine Positions‐Eigenschaft in der PongGame‐Klasse, die mit einem Szenenobjekt für das Rendering verlinkt ist. Erzeuge eine neue Eigenschaft in der PongGame‐Klasse unter Create/Property/Vector3 und nenne diese BallPosition. Setze die Werte der Eigenschaft auf {0, 0.01, 0}, {‐8, 0.01, ‐7}, {8, 0.01, 7}, {0.1, 0.1, 0.1}. Erzeuge außerdem eine Kugel durch Klicken auf den Kugel‐Button in der Scene‐ Werkzeugleiste. Nenne dieses Objekt Ball. Nun wird ein neues Material für den Ball erzeugt. Rechtsklicke dazu auf den Materials‐ Ordner und wähle Create/Basic/Text.fx und benenne das erzeugte Material in BallMaterial. Öffne die Eigenschaften des Ball‐Objektes. Veränder die Local Rotation auf 0, 0, 90 um die Seitenflächen nach oben zeigen zu lassen. Setze das eben erzeugte BallMaterial als Material ein. Setze Use Vertex Colors auf false. Wähle eine diffuse Textur, z.B. MarbleTile2.vtf aus dem Samples‐Ordner. Setze die Eigenschaft UVScale auf 0.5, 0.5 um die Textur besser zu sehen.
Abbildung 37 ‐ Das BallLink‐Diagramm
42
Jetzt wird die Position des Szenenobjektes mit der eben erzeugten Eigenschaft der PongGame‐Klasse verlinkt. Erzeuge ein neues Logik‐Diagramm und nenne es BallLink. Öffne das Diagramm und ziehe die PongGame‐Instanz hinein und positioniere sie auf der linken Seite. Ziehe den Ball in das Diagramm und platziere ihn auf der rechten Seite. Verbinde die Eigenschaft BallPositon von PongGame mit der LocalPositon des Balls. Auch die Größe des Balls soll über eine neue Eigenschaft der PongGame‐Klasse gesteuert werden. Erzeuge in der PongGame‐Klasse diese Eigenschaft über Create/Property/Single und nenne diese BallGröße. Setze die Werte der Eigenschaft auf 0.25, 0.01, 10, 0.01 und setze den In Place Editor wieder auf slider. Öffne wieder das BallLink‐Diagramm. Verbinde den Ausgang von Ball Größe der PongGame‐Klasse mit dem Eingang der Radius‐Eigenschaft des Balls. Das fertige Diagramm ist in Abbildung 37 zu sehen. Nun kann man die Größe des Balls leicht über die Eigenschaft in der PongGame‐Instanz anpassen.
9.5.
Ball bewegen
Der Ball wird nun in einen Körper mit physikalischen Eigenschaften umgewandelt und über die Eigenschaft Velocity (Geschwindigkeit) bewegt. Wähle dazu den Ball im Scene‐Ordner aus. In der Physik‐Werkzeugleiste (Dynamics) klicke auf den Button Make Active Rigid Body. Wenn man nun die Eigenschaften des Balls öffnet, findet man eine neue Kategorie mit dem Namen Active Rigid Body. Hier findet man die physikalischen Eigenschaften. Wir wollen nicht, dass die Geschwindigkeit des Balls gedämpft wird und setzen daher die Eigenschaften Damping und Angular Damping auf 0, 0, 0 (siehe Abbildung 38). Nun wird im OnUpdate‐Skript auch die Position des Balls beschränkt, sodass er das Spielfeld nicht nach oben und unten verlassen kann. Öffne das Skript im Editor und füge Abbildung 38 ‐ Die physikalischen Eigenschaften folgenden Code hinzu: Vector3 ballPosition = (Vector3)context.Site[“BallPosition”]; float ballGroesse = (float)context.Site[“BallGröße”];
Dies schreibt die Ball‐Position und die –Größe in die entsprechenden Variablen. Jetzt wird die Position beschränkt ähnlich wie bei den Schlägern: float halbeBallGroesse = ballGroesse * 0.5f; float maxBallZ = 5.6f; float minBallZ = -5.6f; if ((ballPosition.Z + halbeBallGroesse) > maxBallZ) { ballPosition.Z = maxBallZ – halbeBallGroesse; } else if ((ballPosition.Z – halbeBallGroesse) < minBallZ)
43
{ ballPosition.Z = minBallZ + halbeBallGroesse; }
Nun schreibt man die Position nur noch zurück: context.Site[“BallPosition”] = ballPosition;
Drücke F12 zum Kompilieren des Skriptes. Versuche nun die BallPosition‐Eigenschaft in der PongGame‐Instanz auf 0, 0.01, 10). Jetzt müsste der Ball automatisch wieder an den unteren Rand des Spielfeldes zurückgesetzt werden. Setze die BallPosition wieder auf den Standardwert zurück. Bevor der Ball bewegt wird, muss erst definiert werden, was geschieht, wenn der Ball das Spielfeld am linken oder rechten Rand verlässt. Es soll eine Sieg‐Bedingung gesetzt werden, welcher der beiden Schläger gewonnen hat. Dazu benötigt man weitere Eigenschaften in der PongGame‐Klasse. Erzeuge eine neue Eigenschaft über Create/Property/Boolean und nenne sie SiegLinkerSchläger. Öffne deren Eigenschaften und setze Caption False auf Verloren und Caption True auf Gewonnen. Ändere Is Persistent auf False. Dulpiziere die Eigenschaft SiegLinkerSchläger und nenne die neue Eigenschaft SiegRechterSchläger. Außerdem soll eine Punktzahl gespeichert werden. Erzeuge eine neue Eigenschaft in der PongGame‐Klasse über Create/Property/UInt32 und nenne diese PunkteLinkerSchläger. Öffne deren Eigenschaften und setze Is Persistent auf false. Dupliziere die Eigenschaft und nenne die neue Eigenschaft PunkteRechterSchläger.
Abbildung 39 ‐ Die PongGame‐ Klasse
Lege eine neue Eigenschaft über Create/Property/Boolean in der PongGame‐Klasse mit dem Namen Reset an. Ändere in der Eigenschaft Caption False auf Spielen und Caption True auf Reset.
Der Ball wird über ein Makro zurückgesetzt. Erzeuge dazu im Ordner Macros ein neues Makro über Create/Set Value Macro und nenne es ResetBall. In den Eigenschaften des Makros setzt man die Target Instance auf den Ball im Scene‐Ordner und die Target Property auf LocalPosition in der Local Transform‐Kategorie. In den Eigenschaften des Makros sieht man nun die lokale Position. Setze diese auf 0, 0.01, 0. Bisher wird der Ball an der Position gezeichnet, die die PongGame‐Instanz vorgibt. Dies wird nun verändert, sodass die BallPosition der PongGame‐Instanz vom Ball gelesen wird. Öffne das BallLink‐ Diagramm und lösche die Verbindung zwischen der BallPosition und der LocalPosition. Ziehe eine weitere Instanz des Balles in das Diagramm und platziere sie links von der PongGame‐Instanz. Verbinde den Ausgang LocalPosition des linken Balls mit dem Eingang BallPosition der PongGame‐ Instanz. Teste nun das Makro. Setze die Local‐ Position des Balls auf einen bestimmten Wert, z.B, 4, 0.01, 4.
Abbildung 40 ‐ Das veränderte BallLinkd‐Diagramm
44
Öffne nun das ResetBall‐Makro und ändere die Eigenschaft Play auf true. Der Ball sollte nun wieder in die Ausgangslage zurückgekehrt sein. Erzeuge ein neues Logik‐Diagramm und nenne es MacroLinks. Ziehe das ResetBall‐Makro in das Diagramm und platziere es rechts. Ziehe die PongGame‐Instanz in das Diagramm und platziere sie links. Verbinde den Ausgang Reset der PongGame‐Instanz mit dem Eingang Play des Makros. Wenn nun die Reset‐Eigenschaft des Spiels auf true gesetzt wird, so wird auch der Ball zurückgesetzt. Nun werden die Siegbedingungen in das OnUpdate‐Skript implementiert. Öffne dazu das Skript und füge folgenden Code hinzu: bool reset = (bool)context.Site[“Reset”]; if ((ballPosition.X – halbeBallGroesse) < -8.0f) { reset = true; } else if ((ballPosition.X + halbeBallGroesse) > 8.0f) { reset = true; } else if (reset) { reset = false; }
Dies löst ein Reset aus, sobald der Ball den linken oder rechten Spielfeldrand verlässt. Die Eigenschaft muss jedoch noch zurückgeschrieben werden: context.Site[“Reset”] = reset;
Kompiliere das Skript durch Drücken von F12. Teste das Skript, indem man dem Ball in seinen Eigenschaften in der Active Rigid Body‐Kategorie eine Geschwindigkeit zuweist (Velocity auf der X‐ Achse). Der Ball bewegt sich nun Richtung Spielfeldrand und sobald er das Feld verlässt, sollte er wieder in die Mitte des Feldes zurückgesetzt werden. Setze die Geschwindigkeit und die Position wieder auf die Ursprungswerte. Der Ball soll am oberen und unteren Spielfeldrand abprallen. Dazu wird wieder das OnUpdate‐Skript genommen. Finde die Zeile float minBallZ = -5.6f;
und füge folgenden Code an: IObject ball = context.Site.GetObject(“#Module/Scene/Ball”);
Dies gibt ein Handle auf den Ball im Objektbaum zurück. Man benötigt die Position des Balles: Vector3 ballGeschw = (Vector3)ball[“Velocity”];
Jetzt kann man die Geschwindigkeit im Skript verändern. Finde die if‐else if‐Abfrage in der die Ball‐ Position beschränkt wird und ändere sie folgendermaßen: if ((ballPosition.Z + halbeBallGroesse) > maxBallZ) { ballPosition.Z = maxBallZ – halbeBallGroesse;
45
ballGeschw = Vector3.Reflect(ballGeschw, Vector3.Forward); } else if ((ballPosition.Z – halbeBallGroesse) < minBallZ) { ballPosition.Z = minBallZ + halbeBallGroesse; ballGeschw = Vector3.Reflect(ballGeschw, Vector3.Backward); }
Diese lässt den Ball oben und unten abprallen. Nun muss die Geschwindigkeit nur noch zurückgeschrieben werden: ball[“Velocity”] = ballGeschw;
Drücke F12 zum Kompilieren des Skripts. Überprüfe die Wirkungsweise des Skripts durch Setzen der Geschwindigkeit. Der Ball sollte nun von den Rändern abprallen. Setze die Ball‐Position und – Geschwindigkeit wieder zurück. Ein Makro soll auch die Geschwindigkeit des Balls zurücksetzen. Mehrere Makros können in einem Compound‐Makro vereint werden. Dieses Makro soll die Geschwindigkeit und die Position zurücksetzen. Erzeuge ein neues Makro über Create/Compound Macro. Ziehe das ResetBall‐Makro unter das eben erzeugte Compound‐Makro um es unterzuordnen. Ändere den Namen des ResetBall‐ Makros in ResetBallPosition. Ändere den Namen des Compound‐Makros in ResetBall. Erzeuge unter dem Compound‐Makro ein neues Makro über Create/Set Value Macro und nenne dieses ResetBallGeschw. Öffne die Eigenschaften des eben erzeugten Makros und setze die Target Instance auf den Ball und die Target Property auf Velocity in der Active Rigid Body‐Kategorie. Wenn nun das ResetBall‐Makro aktiviert wird, führt es beide Untermakros aus. Das MacroLinks‐Diagramm muss noch verändert werden um das neue Compound‐Makro auszuführen. Öffne das MacroLinks‐Diagramm. Lösche ResetBallPosition. Ziehe das neue ResetBall‐Makro in den Graphen. Verbinde den Reset‐Ausgang von der PongGame‐Instanz mit dem Play‐Eingang des ResetBall‐Makros. Teste nun das Makro. Gib dem Ball eine Geschwindigkeit. Verlässt der Ball das Spielfeld so müsste er wieder in die Mitte zurückgesetzt werden und die Geschwindigkeit müsste wieder auf 0 gesetzt werden. Der Ball soll nach dem Reset mit einer zufälligen Geschwindigkeit starten. Finde im OnUpdate‐Skript folgende Zeile: else if (reset) { reset = false; }
Ändere diese Zeile in folgenden Code: else if (reset) { ballGeschw.X = Blade3D.Runtime.Operators.MathOperators.GetRandomMinMax(-5, 5); ballGeschw.Z = Blade3D.Runtime.Operators.MathOperators.GetRandomMinMax(-1, 1); if (ballGeschw.X < 0.0f && ballGeschw.X > -2.0f)
46
{ ballGeschw.X = -2.0f; } else if (ballGeschw.X > 0.0f && ballGeschw.X < 2.0f) { ballGeschw.X = 2.0f; } reset = false; }
Drücke F12 zum Kompilieren. Gib dem Ball eine Geschwindigkeit um das Ganze zu starten. Der Ball sollte nun nach Verlassen des Feldes zurückgesetzt werden und eine zufällige Geschwindigkeit bekommen. Setze die Ball‐Position und –Geschwindigkeit wieder auf die Ursprungswerte. Der Ball soll natürlich auch an den Schlägern abprallen. Füge dazu im OnUpdate‐Skript nach der Veränderung der Ball‐Position und –Geschwindigkeit folgenden Code hinzu: float schlaegerBreite = (float)context.Site[„SchlägerBreite“]; float halbeSchlaegerBreite = schlaegerBreite * 0.5f; float halbeSchlaegerHoehe = schlaegerHoehe * 0.5f; if ((ballPosition.X - halbeBallGroesse) < (linkerSchlaegerPosition.X + halbeSchlaegerBreite)) { if ((ballPosition.Z + halbeBallGroesse) > (linkerSchlaegerPosition.Z – halbeSchlaegerHoehe)) { if ((ballPosition.Z – halbeBallGroesse) < (linkerSchlaegerPosition.Z + halbeSchlaegerHoehe)) { if ((ballPosition.X + halbeBallGroesse) > (linkerSchlaegerPosition.X – halbeSchlaegerBreite)) { ballGeschw = Vector3.Reflect(ballGeschw, Vector3.Right); } } } } else if ((ballPosition.X + halbeBallGroesse) > (rechterSchlaegerPosition.X - halbeSchlaegerBreite)) { if ((ballPosition.Z + halbeBallGroesse) > (rechterSchlaegerPosition.Z – halbeSchlaegerHoehe)) { if ((ballPosition.Z – halbeBallGroesse) < (rechterSchlaegerPosition.Z + halbeSchlaegerHoehe)) { if ((ballPosition.X + halbeBallGroesse) < (rechterSchlaegerPosition.X + halbeSchlaegerBreite)) { ballGeschw = Vector3.Reflect(ballGeschw, Vector3.Left); } } } }
Drücke F12 zum Kompilieren. In diesen verschachtelten If‐Abfragen wird geprüft, ob der Ball sich innerhalb der Schläger befindet und wenn ja wird er vom Schläger reflektiert. Das Spiel sollte nun spielbar sein.
47
9.6.
GUI erstellen
Im letzten Abschnitt haben wir der PongGame‐Klasse zwei Eigenschaften hinzugefügt, die die erzielten Punkte speichern. Diese Punkte sollen nun in einer GUI auf dem Bildschirm angezeigt werden. Vorher müssen die Punkte noch in einem Skript inkrementiert werden. Öffne das OnUpdate‐ Skript. Finde den kompletten Code‐Block, der folgenderweise beginnt: if ((ballPosition.X – halbeBallGroesse) < -8.0f) { reset = true; } else if …
Und ändere ihn so um: bool siegLinkerSchlaeger = (bool)context.Site[“SiegLinkerSchläger“]; bool siegRechterSchlaeger = (bool)context.Site[“SiegRechterSchläger“]; if ((ballPosition.X – halbeBallGroesse) < -8.0f) { reset = true; context.Site[“SiegLinkerSchläger”] = true; } else if ((ballPosition.X + halbeBallGroesse) > 8.0f) { reset = true; context.Site[“SiegRechterSchläger”] = true; } else if (reset == true) { ballGeschw.X = Blade3D.Runtime.Operators.MathOperators.GetRandomMinMax(5, 5); ballGeschw.Z = Blade3D.Runtime.Operators.MathOperators.GetRandomMinMax(-1, 1); if (ballGeschw.X < 0.0f && ballGeschw.X > -2.0f) { ballGeschw.X = -2.0f; } else if (ballGeschw.X > 0.0f && ballGeschw.X < 2.0f) { ballGeschw.X = 2.0f; } if (siegLinkerSchlaeger) { uint punkteLinkerSchlaeger = (uint)context.Site[„PunkteLinkerSchläger“]; punkteLinkerSchlaeger++; context.Site[„PunkteLinkerSchläger“] = punkteLinkerSchlaeger; context.Site[„SiegLinkerSchläger“] = false; } if (siegRechterSchlaeger) {
48
uint punkteRechterSchlaeger = (uint)context.Site[„PunkteRechterSchläger“]; punkteRechterSchlaeger++; context.Site[„PunkteRechterSchläger“] = punkteRechterSchlaeger; context.Site[„SiegRechterSchläger“] = false; } reset = false; }
Dieser Codeabschnitt setzt die Sieg‐Eigenschaften auf true, wenn ein Schläger einen Punkt macht. Beim nächsten Update ist die Reset‐Eigenschaft true und es werden die Punkte des gewinnenden Schlägers erhöht. Jetzt werden die Punkte auf der GUI zur Anzeige gebracht. Rechtsklicke auf den User Interfaces‐ Ordner im Objektbrowser und wähle Create/User Interface (klicke im auftauchenden Dialog auf Ok) und nenne die GUI PunkteGUI. Rechtsklicke auf PunkteGUI und wähle Create/Container. Rechtsklicke auf den erzeugten Container und wähle Create/Label. Nenne das Label Spieler1Label. Öffne die Label‐Eigenschaften. Setze die Eigenschaft Text auf Spieler 1:. Setze die Position auf 50, 0 in der Control‐Kategorie. Rechtsklicke auf den Container und wähle Create/Label und nenne es Spieler1Punkte. Öffne die Eigenschaften des eben erzeugten Labels. Setze die Text‐Eigenschaft auf 0 und die Position auf 180, 0. Dupliziere das Spieler1Label und nenne die Kopie Spieler2Label . Setze die Text‐Eigenschaft der Kopie auf Spieler 2: und die Position auf 800, 0. Dupliziere Spieler1Punkte, nenne die Kopie Spieler2Punkte und setze die Position auf 910, 0. Abbildung 41 ‐ Die Punkteanzeige Erzeuge ein neues Logik‐Diagramm und nenne es PunkteGUILink. Ziehe die PongGame‐Instanz, das Spieler1Punkte‐ und das Spieler2Punkte‐Label in das Diagramm. Verbinde die Ausgänge der Eigenschaften Punkte Linker Schläger und Punkte Rechter Schläger der PongGame‐Instanz mit den entsprechenden Text‐Eingängen der Labels wie in Abbildung 42 dargestellt. Nun zeigen die Labels den aktuellen Punktestand an. Der GUI wird nun ein Button hinzugefügt, der das ganze Spiel zurücksetzt und neu startet. Rechtsklicke auf den Container unter PunkteGUI und wähle Create/Button. Nenne den Button ResetSpiel. Setze die Text‐ Eigenschaft des Buttons auf Spiel Spiel. Ändere die BackColor auf Rot, setze die Position auf 465, 10 und ändere die Größe (Size) auf 170, 60. Ein neues Compound‐Makro wird die Reset‐ Eigenschaft der PongGame‐Instanz auf true Abbildung 42 ‐ Das PunkteGUILink‐Diagramm und die Punktstände auf 0 setzen. Erzeuge ein neues Compound‐Makro und nenne es ResetSpiel. Erzeuge ein Untermakro über Create/Set Value Macro und nenne es ResetPongGame. Setze die Target Instance des Untermakros auf die PongGame‐ Instanz und die Target Property auf Reset. Nun wird die Reset‐Option angezeigt, ändere diese auf Reset. Erzeuge im ResetSpiel‐Makro ein neues Untermakro über Create/Set Value Macro und nenne
49
es ResetPunkteSpieler1. Setze die Target Instance auf die PongGame‐Instanz und die Target Property auf PunkteLinkerSchläger. Erzeuge auf die gleiche Weise ein weiteres Untermakro für den Punktestand des rechten Schlägers. Dies sollte das Spiel zurücksetzen. Man könnte weiterhin noch 2 Untermakros erzeugen, die außerdem noch die Schlägerpositionen noch zurücksetzen. Das Makro wird nun über ein Logik‐ Diagramm mit dem Button verbunden. Erzeuge ein neues Logik‐Diagramm und nenne es ResetSpielLinks. Ziehe den ResetSpiel‐Button und das ResetSpiel‐Compound‐Makro in das Diagramm. Verbinde den ClickEvent‐Ausgang des Buttons mit dem Play‐Eingang des Makros. Nun muss nur noch der Ball zurückgesetzt werden. Dazu gibt es bereits das ResetBall‐Makro. Dieses muss nur noch als Untermakro in das ResetSpiel‐Makro gezogen werden. Viel Spaß beim Spielen!
Quellen: • •
•
Die Blade3D‐Online‐Hilfe Die Blade3D‐Wiki ( http://wiki.blade3d.com ), aus der auch das Pong‐Tutorial entnommen wurde Das Blade3D‐Internetforum (http://www.xnamagic.com/Community/Forums/tabid/75/Default.aspx )
50