Montag, 30. März 2015

Super Mario 64 mit Unity als Browsergame

Roystan Ross hat mit der Unity Engine das erste Level aus dem Nintendo 64 Klassiker Super Mario 64. Es sieht nicht nur erstaunlich gut aus (von der Grafik deutlich besser als das Original). Es spielt sich auch prima. Die Animationen wirken identisch mit dem Original und auch den Sound ist man gewohnt.


Auf seinem Blog schreibt Ross viel zu Unity. Vor allem natürlich zu seinem Projekt Super Mario 64 HD. Aber auch andere Themen im Hinblick zu Spielerstellung mit Unity. Beispielsweise hat er den Charakter Controller aus dem Mario Spiel also Customer Version freigegeben und jedem zur Verfügung gestellt.















Achja, Super Mario 64 HD kann man über diesen Link direkt im Browser spielen (Unity Player wird evtl. geblockt --> zulassen).

Montag, 23. März 2015

Visualisierung kostenlos

An dieser Stelle möchte ich noch auf Tools etc. zur Visualisierung verweisen, welche kostenlos sind. Das Programm R habe ich bereits in älteren Beiträgen beschrieben.

Google Developers bietet unter der Chart Gallery einige Tools zur Visualisierung an. Dank der Verbindung von JavaScript HTML und CSS lassen sich diese Ergebnisse einfach in eine Website integrieren. Der vorherige Post zum Thema Treemap habe ich ebenfalls mit diesem Google Tool erstellt.

Eine weitere JavaScript Bibliothek gibt es unter d3js.org.

Maps, Stocks und Charts lassen sich sich wohl auch mit dem Tool auf highcharts.com ganz gut und ansehnlich erstellen. Selbst getestet habe ich es nicht. Die Beispiele sehen aber sehr interessant aus und für nichtkommerzielle Zwecke ist es kostenlos.

Natürlich gibt es noch weitaus mehr Toos zum Visualisieren. Eine Zusammenstellung dazu habe ich hier gefunden. Dort werden auch Tools wie ManyEyes, Processing, Gapminder, WolframAlpha und viele mehr vorgestellt und verlinkt.

Samstag, 21. März 2015

Visualisierung mit Google Treemap

Seitdem ich die Treemaps auf MarketWatch.com gesehen habe, wollte ich in diese Richtung visualisieren. Aber welche Daten soll ich dafür verwenden?






















Da ich fast täglich die "NBA Game Time" App auf meinem Handy benutze, ist mir aufgefallen, dass die National Basketball Association eine riesige Datenbank voller Statistiken besitzt. Auf nba.com/stats kann man zu ziemlich allen möglichen Bezügen Statistiken abrufen. Leider ist ein Export im CSV-Format meines Wissens nicht möglich.

















Da ich keine Statistik visualisieren wollte, die es schon gibt, musste ich mir etwas ausdenken. Da sich die Playoffs nähern und die Presse oft davon schreibt, wie stark der Westen im Vergleich zum Osten ist, dachte ich mir, gehe ich der Sache nach. Außerdem gibt es seit der Saison 2011/2012 eine Reihe neuer Statistiken in der NBA. Zum Beispiel die Advanced Statistics. Diese Statistiken wollen vor allem die Effizienz der Spieler messen. Auch ist es wesentlich schwerer die Defense als die Offense zu messen. Dafür kommen zum Beispiel spezielle Kameras zum Einsatz, wie in diesem Bericht erwähnt wird.
Die Statistik mit der kompliziertesten Formel ist das Player Efficiency Rating (PER):
PER = (LgPace/TmPace) * (15/LgPER) * (1/MP) * [3P + (AST*0,67) + (FG*{2-[(TmAST/TmFG)*0,588]}) + (FT*0,5*{2-0,33*(TmAST/TmFG)}) + (DefREB*VOP*LgOffREB%) + (OffReb*VOP*LgDefREB%) + (STL*VOP) + (BLK*VOP*LgDefREB%) - (TO*VOP) - [(FGA-FG)*VOP*LgDefREB%] - {(FTA-FT)*VOP*0,44*[0,44+(0,56*LgDefREB%)]} - {PF*[(LgFT/LgPF)-((LgFTA/LgPF)*0,44*VOP)]}]. 
Somit sollen sich auch Statistiken unterschiedlicher Epochen vergleichen lassen. Und wer hätte es gedacht,  auf dem ersten Platz steht Michael Jordan mit einem Wert von 27,91.

In einigen Statistiken werden aktuell verletzte Spieler nicht aufgeführt. Somit kann es sein, dass beispielsweise ein PER-Wert eines Spielers nicht automatisch verfügbar ist und manuell berechnet werden müsste. Aus diesem Grund habe ich mich entschieden die EFF (Efficiency) zu verwenden. Die Effizienz stellt eine Vergleichsgröße dar, mit der die Leistung eines Spielers bewertet und vergleichbar gemacht werden kann (und ist im Vergleich zur PER einfach und schneller zu berechnen).
Effizienz = (Punkte + Rebounds + Assists + Steals + Blocks) - ((Anzahl Wurfversuche - Anzahl verwandelte Würfe) + (Anzahl Freiwurfversuche - Anzahl verwandelte Freiwürfe) + Turnover)















In Google Treemaps kann man Grundsätzlich zwei Parameter einstellen. Die Größe eines Vierecks und die Farbe. Außerdem kann man die Vierecke beschriften und per Mousover den Wert, welcher dahinter liegt, anzeigen lassen. Meine Visualisierung soll folgendes veranschaulichen:
  1. Eine Gegenüberstellung der Western Conference und Eastern Conference, anhand der Win%. Wie viel Prozent der Spiele hat ein Team gewonnen? Je höher desto größer das Viereck der jeweiligen Conference. Die Farbe wird durch die Anzahl der Siege berechnet. 0% Siege = Farbe Pink, 100% Siege = Farbe Blau.
  2. Die Conferences sind in Teams eingeteilt (Hiebei jeweils nur 8 Teams - die acht, welche aktuell in die Playoffs einziehen würden). Die Teams werden wiederum durch die Spieler bewertet.
  3. Jedem Team habe ich die fünf Spieler der Starting Lineup zugewiesen. Hier wollte ich die Korrelation von durchschnittlicher Spielzeit (MIN) und Effizienz (EFF) darstellen. Je mehr Spielzeit, desto größer das Viereck. Umso eine höhere EFF, desto blauer das Viereck.
Mein Resultat sieht vorerst so aus (auf Result klicken - im Treamap ist Linksklick = vor, Rechtsklick = zurück): 




Dabei bestehen noch einige Probleme. Der Mousovereffekt muss noch optimiert werden (Beschriftung). Komfortabel wäre es natürlich auch, die Daten als JSON-Datei einzubinden. Als Child-Elemente von den Spielern wollte ich noch weitere Statistiken anfügen, die ich schon angefangen habe vorzubereiten:

      ['Points',    'Harrison Barnes',            10.5,                              9.1],
          ['Rebounds',    'Harrison Barnes',            5.6,                              9.1],
          ['Assists',    'Harrison Barnes',            1.4,                              9.1],
       
          ['Points',    'Andrew Bogut',            6.2,                              11.3],
          ['Rebounds',    'Andrew Bogut',            8,                              11.3],
          ['Assists',    'Andrew Bogut',            2.6,                              11.3],
       
          ['Points',    'Stephen Curry',            23.3,                              17.8],
          ['Rebounds',    'Stephen Curry',            4.3,                              17.8],
          ['Assits',    'Stephen Curry',            7.9,                              17.8],
       
          ['Points',    'Draymond Green',            11.8,                              11.3],
          ['Rebounds',    'Draymond Green',            8.1,                              11.3],
          ['Assists',    'Draymond Green',            3.6,                              11.3],
       
          ['Points',    'Klay Thompson',            21.9,                              12.7],
          ['Rebounds',    'Klay Thompson',            3.2,                              12.7],
          ['Assists',    'Klay Thompson',            2.9,                              12.7],
       
          ['Points',    'Tony Allen',            8.7,                              8.7],
          ['Rebounds',    'Tony Allen',            4.4,                              8.7],
          ['Assists',    'Tony Allen',            1.4,                              8.7],

Leider ist das so nicht möglich, da identische Children nicht auf unterschiedliche Parents zugreifen können. Eine Lösung hierzu ist mir bisher noch nicht eingefallen. Ich werde aber daran arbeiten und Neuigkeiten wieder hier berichten.

Freitag, 20. März 2015

Fertiges Spiel in Unity

Nachdem scripten ist es nur noch ein Schritt bis zum fertigen Spiel. Dieser ist dank Unity verhältnismäßig einfach. Über File --> Build & Run kann man das Spiel generieren. Hier kann man auch noch auswählen, für welche Plattform es erstellt werden soll. Ich habe es einmal als .app für Mac konfiguriert und einmal als Browser Spiel.
Unter diesem Link habe ich das Browser-Game bereitgestellt. Hier muss man beide Dateien downloaden. Anschließend die HTML-Datei öffnen, dann der Anweisung folgen und den Unity-Player herunterladen. Anschließend nur noch darauf achten, dass Pop-Ups nicht geblockt werden.

Als Anschauungsmaterial habe ich hier ein Ingame-Video:


Abschließend möchte ich noch ein kurzes Fazit zum gesamten Projekt loswerden:
Unity und Blender bieten eine Vielzahl an Möglichkeiten, wie man etwas macht. Tutorials im Internet unterstützen dabei enorm. Man kann sich viel anschauen und für sein eigenes Projekt anpassen. Die Community ist wirklich fantastisch. Ebenso wie die beiden erwähnten Programm. Vor allem Blender hat einen hohen Einstiegs- und zu Beginn vor allem Frustrationsgrad. Doch nach einer Weile kommt man damit ganz gut klar.
Auch muss ich sagen, dass ich mich mit den Themen, welche ich behandelt habe, nun ganz gut zurecht finde. Nach meinem Gefühl ist das aber nicht einmal ein Bruchteil von dem Gesamtmöglichen, was die Programme bieten. Aber das freut mich auch, da ich einen Einstieg gefunden habe und es jetzt eigentlich erst richtig losgehen kann.
An dieser Stelle bedanke ich mich bei meinem Projektpartner Roland. Es hat sehr viel Spaß gemacht und ohne unsere Zusammenarbeit wäre dieses Projekt wohl nicht zustande gekommen. Ebenfalls danke an die PH, für die Räumlichkeiten, Hardware und Software.

Zu unserem Spiel möchte ich sagen, es sieht zwar optisch nicht schön aus, hat einige Bugs, aber es läuft. Wir haben es geschafft, aus Blender 3D-Modelle, samt Animationen zu generieren, diese in Unity zu importieren und per Script daraus ein Spiel zu erstellen.

Zu aller Letzt noch zwei offene Themengebiete, dich ich unbedingt noch nennen möchte.
  1. Wieso haben wir mit C# und nicht mit Java Script programmiert? - Das war mehr oder weniger Zufall. Unser erster Beispielcode war in C#, dann haben wir einfach gedacht, machen wir so weiter. Die offiziellen Unity Tutorials zeigen immer beide Varianten an. Code in C# und JS. Da wird man hervorragend unterstützt. 
  2. Die neuste Version von Unity (Unity 5) bietet weitere tolle Features, die wir aufgrund der Vorgängerversion nicht nutzen konnten. Wir wollten mitten im Projekt kein Risiko eingehen und haben deshalb kein Update des Programms durchgeführt. Ein neues Feature, welches uns durchaus hilfreich gewesen wäre ist die UI Scrollbar. Leicht modifiziert hätten wir so eine interaktive Healtbar einbauen können, welche nach jedem Treffer abnimmt. Ein Tutorial dazu gibt es hier.

Scripten in Unity

Bei der Programmierung von Scripten stellt Unity mit MonoDevelop automatisch eine hervorragende integrierte Entwicklungsumgebung. Ähnlich wie Eclipse bietet MonoDevelop alles was man zum Programmieren benötigt.

Um ein Script in Unity zu erstellen, geht man im Inspector im unteren Teil wieder auf den Button "Add Component" und wählt "New Script. Nun kann man noch die Programmiersprache auswählen und das Script erstellen. Es erscheint von nun an bei den Assets. Ein Doppelklick hier auf die Datei und MonoDevelop wird geöffnet (In der Unity Version 4.3 kommt es hierbei zu Problemen und MonoDevelop lässt sich nicht starten. Ein Update behebt den Fehler). 








Die Variablen (Aim, Health, Movement Speed, Game Over und Sip Health) wurden von uns im Script erstellen und erscheinen, wie im Screenshot zu sehen, auch in der Unity Umgebung.

Da wir unseren Animationen bereits in Blender verschiedene Bezeichnungen gegeben haben, mussten wir für jeden Charakter ein einzelnes Script schreiben. Bei dem geringen Umfang war das kein Problem. Aber trotzdem der Tip: Schon zu Beginn des Projekts überlegen, wie das Script ungefähr aussehen soll. Dementsprechend schon in Blender die Animationen identisch benennen.

Mein Script sah dann so aus:



























Zur Erklärung:
  • anim vom Typ Animation belegen wir mit unseren Animationen
  • Die Variable healt wird mit 100 gefüllt und soll sich mit jedem Schlag um 10 verringern.
  • Die Variable movementSpeed haben wir festgelegt und auf 10 gesetzt, damit die Charaktere etwas schneller sind.
  • gameOver ist ein Textfeld und wird bei Spielende angezeigt.
  • dispHealth ist ebenfalls ein Textfeld und zeigt die Healthangabe beider Charaktere in der jeweiligen oberen Ecke.
An dieser Stelle soll gesagt werden, dass sich die offiziellen Unity Tutorials als sehr hilfreich herausgestellt haben. Ein Video-Tutorial zum Thema Collider habe ich hier nachfolgend als Beispiel eingestellt.


Weiter in der Erklärung des Scripts. 

void OnTriggerStay (Collider collider)
        {
                if (Input.GetKeyDown ("f") && health >= 0) {
                        health -= 10;
                
                }
Den dritten Box-Collider haben wir auf Trigger gestellt. Kommt dieser Collider in Kontakt mit dem Collider des Gegners, ist folgende If-Anweisung möglich: Drückt der Gegner die "f" Taste auf der Tastatur wird die Healthvariable um -10 verringert pro Tastendruck.


    void OnCollisionExit (Collision collision)
        {
                //Bei Berührung mit einem anderen Rigidbody entstehen Krafteinwirkungen die wir nach der Collision elliminieren
                rigidbody.velocity = Vector3.zero;
        
        }

Nach der Collision werden alle Kräfte (forces) des Vectors3 (3D Vector in Unity) auf 0 gestellt. Das ist nötig, weil sich die Modelle aufgrund des Rigidbodies sonst weiterbewegen. In unserem Falls sind sie nach einer Berührung langsam nach hinten gerutscht. 

void Update ()
        {
                dispHealth.text = "Dominator: " + health.ToString () + " HP";
                //KO-Bedingung
                if (health <= 0) {
                        Time.timeScale = 0;
                        gameOver.text = "Rageland gewinnt!";

In void Update haben wir die Anweisung, dass wenn die Healthvariable kleiner gleich O ist der timeScale auf 0 gesetzt wird und gamOver aufgerufen wird. Das hat zufolge, dass das Spiel gestoppt wird und das gameOver Textfeld erscheint. Das Besondere hierbei, die Healthanzeige des Gegners ist sozusagen im eigenen Script.

else  if (Input.GetKey ("j")) {

                        //Positionsänderung erfolgt anhand der vergangenen animationszeit * Bewegungsgeschwindigkeit
                        //Crossfade als Animationsanweisung sorgt dafürdass die Übergänge zwischen den Animationen erstellt werden
                        anim.CrossFade ("Armature|Rueckwaerts");
                        transform.position += new Vector3 (movementSpeed * Time.deltaTime00);
                } else if (Input.GetKey ("h")) {
            
                        anim.CrossFade ("Armature|Vorwaerts");
                        transform.position += new Vector3 (-1 * movementSpeed * Time.deltaTime00);
                } else if (Input.GetKey ("l")) {
            
                        anim.CrossFade ("Armature|Jab");            
            
Ist das nicht der Fall gelten folgende Else-Anweisungen. Der Tastaturbefehl "j" dient zur Bewegung Rückwärts, solange die Taste gedrückt wird. Gleichzeitig wird die entsprechende Animation (hier: Armature|Rueckwaerts) abgespielt. Die Multiplikation movementSpeed*Time.deltaTime löst aus, dass sich der Charakter um 10 Pixel pro Sekunde auf der X-Achse bewegt. Mit der Taste "h" kann man ihn vorwärts bewegen, mit "l" wird der Schlag ausgeführt.

else {
            
                        anim.CrossFade ("Armature|Fightposition");
                }

Wird nichts gedrückt, wird die Animation "Armature|Fightposition" abgespielt. Wie hier zusehen ist, haben wir bei allen Animationen einen CrossFade hinzugefügt. Das sorgt für eine weicheren Übergang zwischen den einzelnen Animationen.

Box Collider & Rigidbody in Unity

Bevor wir die Charaktere per Tastatureingabe über ein Script ansteuern können, sind noch ein paar Vorbereitungen zu treffen.

Den Modellen haben wir einen Rigidbody zugewiesen (Add Components --> Physiks --> Rigidbody) und sie somit mit physikalische Eigenschaften versehen. Den Wert Mass haben wir auf auf den geringsten Wert von 0,0000001 gestellt. Den restlichen Einstellungen haben wir fast alle auf Default gelassen. Die Constrains (einzelne Bewegungsachsen) haben wir alle gefreezed, bis auf die X-Achse. Unser Charakter soll sich nämlich nur auf dieser Achse vor und zurück bewegen können. Wie in einem klassischen Beat' em Up wie Steet Fighter und Co.















Eine Erklärung zu allen Rigidbody-Einstellungen gibt es hier. Zusätzlich haben wir beiden Charakter einen Box Collider (grüner Kasten) zugewiesen. Dieser hat gleich zwei Funktionen: (1) Zum einen haben wir die beiden Collider-Größen in X-Achste etwas erhöht, da wir anfangs das Problem hatten, dass die Charakter aneinander vorbei rutschten, wenn sie frontal auf sich zugingen. (2) Und zum anderen brauchen wir den Collider für das Script. So können wir gewisse Abhängigkeiten bei Collider Berührung erstellen und abfragen.











Dem anderen Charakter haben wir noch einen zusätzlichen Collider mitgegeben. Dieser ist, wie auf dem folgenden Screenshot zu sehen, etwas vor dem Modell platziert. Der Collider simuliert im Grunde die Reichweite der Schlaghand. Das spielt beim scripten noch eine wichtige Rolle und wird im nächsten Beitrag beschrieben.












Charakter in Unity integrieren

Nach einigen Feinarbeiten am 3D-Modell steht nun der Export nach Unity an. Dazu habe ich den Charakter in Blender im Autodesk FBX (.fbx) exportiert. Diese Datei enthält das 3D-Modell, die Armature (Bones) und alle Animationen.
In Unity kann man diese Datei anschließend per Drag & Drop zu den Assets ziehen. Nun muss man die Texture noch einmal neu Verknüpfen. Dazu in der Hierarchy auf der linken Seite den Charakter auswählen, dann den eigentlichen Body (Mesh) anklicken. In meinem Fall heißt er eye.green (durch das importierte Auge, gab es Bennenungskomplikationen). 
















Beziehungsweise hat Unity meinen Charakter in fünf Dateien (Mesh Part0 - 1) unterteilt, da mein Model zuviel Vertices (Punkte) bzw. Faces (Flächen) besitzt. Durch mehrfache Anwendung des Subdivision Surface Modifiers hab ich meinen Charakter in sehr viel Polygone unterteilt, was mir jetzt nachteilig erscheint. Deshalb der Tip, sparsam mit diesem Modifier umgehen.

Hat man das Mesh ausgewählt, kann man im Inspector auf der rechten Seite die Textur verknüpfen. Dazu einfach die PNG-Texturdatei, welche auch in Blender verwendet wird, in das Feld rechts unten ziehen, bzw. über "Select" auswählen.















Im Inspector kann man ebenfalls, die Positionierung und Größe des Charakters auswählen. Wir haben ein Terrain gebastelt und die beiden Modelle auf einem Berg positioniert. Dazu mussten wir sie noch um den Faktor 200 vergrößern.














Auf dem vorherigen Screenshot sind auch schon die ganzen Animationen gelistet, die Blender ohne Probleme übernommen hat. Dabei ist es wichtig, dass man in den Import Settings unter "Rig" den Animation Type auf "Legacy" einstellt (Die Import Settings erreicht man, indem man auf den Charakter unter Assets klickt).








Legacy bedeutet, dass die Animationen aus Blender vererbet werden. Unity bietet auch die Möglichkeit einer automatischen Knochenerkennung. Stellt man den Animation Type auf "Humanoid" erkennt Unity die Bones des 3D-Modells und verknüpft sie mit dem sogenannten Unity Avatar.

Unter dem Punkt Animations, kann man alle Animationen des Modells ansehen, abspielen und sogar schneiden. In meinem Fall musste ich den Jab um einen Frame am Anfang kürzen. Auch kann man Loop Frames automatisch einfügen lassen, um die Bewegung runder darzustellen.















Tip: Bei mehreren Modellen, für jedes einen eigenen Ordner in den Assets anlegen. Jeden Charakter einzeln nacheinander einfügen, Textur zuweisen und positionieren.

In Unity sah das Ganze dann so aus:












Mein Charakter musste mit dem Rücken zu dem anderen Charakter positioniert werden, damit die Animationen später im Spiel auf die richtige Seite abgespielt werden. Mehr dazu aber im nächsten Beitrag...