Unity

Entwickeln Ihres ersten Spiels mit Unity und C#

Adam Tuliper

Laden Sie die Codebeispiele herunter

Als Softwarearchitekt habe ich viele Systeme geschrieben und das Reverse-Engineering von systemeigener Codeschadsoftware vorgenommen. Zudem ich Dinge auf der Codeseite im Allgemeinen lösen. Als es um das Entwickeln von Spielen ging, fühlte ich mich jedoch am Anfang ein wenig verloren. In der Windows-Frühzeit habe ich einige systemeigene Codegrafikprogrammierungen vorgenommen, und das war alles andere als lustig. Ich habe dann auf Grundlage der DirectX-Entwicklung begonnen, aber festgestellt, dass es ungeachtet der großen Leistungsfähigkeit für meine Ansprüche zu viel Code war.

Eines Tages beschloss ich, mich mit Unity zu beschäftigen, und ich fand heraus, es kann einige herausragende Dinge. Dieser ist der erste der aus vier Artikeln bestehenden Reihe, in der die Grundlagen und Architektur von Unity erörtert werden. Ich werde die Erstellung von 2D- und 3D-Spielen aufzeigen und wie sie für die Windows-Plattformen erstellt werden.

Was ist Unity?

Unity ist ein 2D-/3D-Modul und ein -Framework, das Ihnen ein System für das Entwickeln von Spielen oder App-Szenen für 2D, 2,5D und 3D an die Hand gibt. Ich unterscheide zwischen Spielen und Apps, da ich nicht nur einfache Spiele gesehen habe, sondern Trainingssimulationen, Ersthelferanwendungen und andere geschäftsorientierte Anwendungen, die mit Unity entwickelt wurden, welche mit dem 2D-/3D-Raum interagieren müssen. Unity ermöglicht Ihnen, mit ihnen nicht nur über Code zu interagieren, sondern auch über visuelle Komponenten, und es ermöglicht Ihnen u. a., sie in jede große Mobilplattform zu exportieren, und zwar kostenlos. (Es gibt auch eine großartige Pro-Version, die jedoch nicht kostenlos ist. Aber Sie können auch mit der kostenlosen Version beeindruckende Ergebnisse erzielen.) Unity unterstützt alle Haupt-3D-Anwendungen und viele Audioformat und erkennt sogar das Photoshop-Format (PSD), sodass Sie eine PSD-Datei einfach per Drag-and-Drop in ein Unity-Projekt einfügen können. Unity ermöglicht Ihnen u. a., Assets zu importieren und zu assemblieren, Code zu schreiben, um mit Ihren Objekten zu interagieren, oder Animationen für die Verwendung mit einem erweiterten Animationssystem zu erstellen oder zu importieren.

Wie auch in Abbildung 1 ersichtlich, stellt Unity die plattformübergreifende Unterstützung sicher. Ferner können Sie Plattformen buchstäblich mit einem Klick ändern, obwohl, um realistisch zu sein, ein wenig mehr Aufwand erforderlich ist (beispielsweise das Integrieren in jeden Store für In-App-Käufe).

durch Unity unterstützte Plattformen
Abbildung 1 – durch Unity unterstützte Plattformen

Der wahrscheinlich leistungsstärkste Bestandteil von Unity ist der Unity Asset Store, der wohl beste Asset-Marktplatz in der Spielewelt. Darin finden Sie alle Ihre Anforderungen an Spielkomponenten, wie beispielsweise Artwork, 3D-Modelle, Animationsdateien für Ihre 3D-Modelle (siehe Mixamos Inhalt im Store für mehr als 10.000 Bewegungen), Toneffekte und vollständige Titel, Plug-Ins – dazu zählen auch solche wie das MultiPlatform-Toolkit, das bei der Unterstützung mehrerer Plattformen helfen kann –, visuelle Skripterstellungssysteme wie PlayMaker und Behave, erweiterte Shader, Texturen, Partikeleffekte usw. Die Unity-Oberfläche ist vollständig skriptfähig, wodurch viele Drittanbieter-Plug-Ins direkt in die Unity-GUI integriert werden können. Die meisten, wenn nicht sogar alle, professionellen Spieleentwickler verwenden einige Pakete aus dem Asset Store, und wenn Sie etwas Angemessenes anzubieten haben, können Sie dies dort auch veröffentlichen.

Was Unity nicht ist

Ich zögere mit der Beschreibung dessen, was Unity nicht ist, da dies immer wieder angezweifelt wird. Unity ist jedoch standardmäßig kein System, in dem Sie Ihre 2D-Assets und 3D-Modelle (mit Ausnahme von Geländen) entwickeln können. Sie können ein paar Zombies in einer Szene platzieren und sie steuern, aber Sie würden im Unity-Standardtool keine Zombies erstellen. So gesehen ist Unity kein Asset-Erstellungstool wie Autodesk Maya oder 3DSMax, Blender oder sogar Adobe Photoshop. Es gibt jedoch wenigstens ein Drittanbietermodellierungs-Plug-In (ProBuilder), das Ihnen das direkte Modellieren von 3D-Komponenten in Unity ermöglicht. Ferner stehen 2D-Welterstellungs-Plug-Ins wie der 2D Terrain Editor für das Erstellen von gekachelten 2D-Umgebungen zur Verfügung, und Sie können auch Gelände in Unity mithilfe der Terraintools entwerfen, um großartige Landschaften mit Bäumen, Gras, Bergen usw. zu erstellen. Ich muss abermals zögern, wenn es darum geht, die Grenzen von Unity aufzuzeigen.

Wie passt Microsoft dazu? Microsoft und Unity arbeiten eng zusammen, um eine großartige Plattformunterstützung über den Microsoft-Stapel hinweg sicherzustellen. Unity unterstützt eigenständige ausführbare Windows-Dateien, Windows Phone, Windows Store-Anwendungen, Xbox 360 und Xbox One.

Erste Schritte

Laden Sie die neueste Version von Unity herunter, und besorgen Sie sich eine Maus mit zwei Tasten und einem klickbaren Mausrad. Es steht ein einzelner Download zur Verfügung, der für den kostenlosen oder den Pro-Modus lizenziert werden kann. Die Unterschiede zwischen den Versionen können Sie unter unity3d.com/unity/licenses nachvollziehen. Der Editor, der die Unity-Hauptoberfläche ist, wird auf Windows (einschließlich Surface Pro), Linux und OS X ausgeführt.

Die wirkliche Spieleentwicklung mit Unity erläutere ich im nächsten Artikel. Zunächst möchte ich die Unity-Oberfläche, -Projektstruktur und -Architektur erörtern.

Architektur und Kompilierung

Unity ist ein systemeigenes auf C++ basierendes Spielemodul. Sie schreiben Code in C#, JavaScript (UnityScript) oder seltener in Boo. Ihr Code, nicht der Unity-Modulcode, wird auf Mono oder Microsoft .NET Framework ausgeführt, der JIT-kompiliert (Just-in-Time) ist (mit Ausnahme von iOS, was den JIT-Code nicht zulässt und durch einen Mono-zu-systemeigenen Code unter Verwendung der AOT-Kompilierung (Ahead-of-Time) kompiliert ist).

Unity ermöglicht Ihnen, Ihr Spiel in der IDE zu testen, ohne Exporte oder Builds vornehmen zu müssen. Beim Ausführen von Code in Unity verwenden Sie die Version 3.5 von Mono, deren API-Kompatibilität in etwa mit der von .NET Framework 3.5/CLR 2.0 übereinstimmt.

Sie können Ihren Code in Unity bearbeiten, indem Sie in der Projektansicht auf eine Codedatei doppelklicken, wodurch der standardmäßige plattformübergreifende Editor Mono-Develop geöffnet wird. Sie können aber auch bei Bedarf Visual Studio als Ihren Editor konfigurieren.

Sie debuggen mit MonoDevelop oder verwenden UnityVS – ein Drittanbieter-Plug-In für Visual Studio. Sie können Visual Studio ohne UnityVS nicht als Debugger verwenden. Wenn Sie Ihr Spiel debuggen, debuggen Sie nämlich nicht "Unity.exe", sondern eine virtuelle Umgebung in Unity mithilfe eines Soft Debuggers, der Befehle ausstellt und Aktionen ausführt.

Zum Debuggen starten Sie MonoDevelop in Unity. MonoDevelop verfügt über ein Plug-In, das eine Verbindung zurück zum Unity-Debugger öffnet und Befehle dazu ausstellt, nachdem Sie "Debug (Debuggen) | Attach to Process in MonoDevelop (An Prozess in MonoDevelop anfügen)" ausgewählt haben. Mit UnityVS können Sie stattdessen den Visual Studio-Debugger zurück zu Unity verbinden.

Wenn Sie Unity erstmals öffnen, wird das Projektdialogfeld angezeigt (siehe Abbildung 2).

der Unity-Projekt-Assistent
Abbildung 2 – der Unity-Projekt-Assistent

Im Projektdialogfeld geben Sie den Namen und Speicherort Ihres Projekts (1) an. Sie können beliebige Pakete in Ihr Projekt (2) importieren, Sie müssen hier nichts deaktivieren. Die Liste wird nur zwecks besserer Benutzerfreundlichkeit bereitgestellt. Sie können auch später ein Paket importieren. Ein Paket ist eine .unitypackage-Datei, die vorgefertigte Ressourcen – Modelle, Code, Szenen, Plug-Ins (alles, was Sie in Unity packen können) – enthält, und Sie können Sie einfach wiederverwenden oder bereitstellen. Deaktivieren Sie hier keine Einstellungen, wenn Sie nicht wissen, wofür sie steht, auch wenn Ihre Projektgröße dadurch manchmal beträchtlich ansteigen kann. Abschließend wählen Sie zwischen 2D oder 3D (3) aus. Dieses Dropdownmenü ist relativ neu in Unity, welches bis vor Kurzem keine erheblichen 2D-Spieltools umfasste. Bei der Festlegung auf 3D ziehen die Standardeinstellungen ein 3D-Projekt vor, was seit jeher ein typisches Unity-Verhalten darstellt und somit nicht weiter erläutert werden muss. Bei Auswahl von 2D ändert Unity ein paar anscheinend kleine (aber eigentlich große) Dinge, die ich später im 2D-Artikel dieser Reihe in Augenschein nehmen werde.

Diese Liste wird aus .unitypackage-Dateien in bestimmten Speicherorten auf Ihrem System aufgefüllt. Unity bietet eine Handvoll davon für die Installation. Sämtliche Inhalte, die Sie aus dem Unity Asset Store herunterladen, werden auch als .unitypackage-Datei bereitgestellt und lokal auf Ihrem System unter "C:\Benutzer\<Benutzername>\AppData\­Roaming\Unity\Asset Store" zwischengespeichert. Als solche werden sie in dieser Liste angezeigt, sobald sie auf Ihrem System vorhanden sind. Sie könnten einfach auf eine beliebige .unitypackage-Datei doppelklicken, und sie würde in Ihr Projekt importiert werden.

Unter Verwendung der Unity-Oberfläche klicke ich auf das Dialogfeld zum Erstellen (siehe Abbildung 2), sodass ein neues Projekt erstellt wird. Das standardmäßige Unity-Layoutfenster wird in Abbildung 3 gezeigt.

das standardmäßige Unity-Fenster
Abbildung 3 – das standardmäßige Unity-Fenster

Folgendes wird angezeigt:

  1. Project (Projekt): Sämtliche Dateien Ihres Projekts. Sie können Dateien per Drag-and-Drop aus dem Explorer in Unity einfügen, um Ihrem Projekt Dateien hinzuzufügen.
  2. Scene (Szene): Die derzeit geöffnete Szene.
  3. Hierarchy (Hierarchie): Sämtliche Spielobjekte in der Szene. Beachten Sie die Verwendung des Begriffs "GameObjects" und das Dropdownmenü "GameObjects".
  4. Inspector (Prüfung): Die Komponenten (Eigenschaften) des ausgewählten Objekts in der Szene.
  5. Toolbar (Symbolleiste): Ganz links befinden sich "Pan" (Schwenken), "Move" (Verschieben), "Rotate" (Drehen), "Scale" (Skalieren), und in der Mitte befinden sich "Play" (Wiedergabe), "Pause" und "Advance Frame (Langsamer Vorlauf)". Durch das Klicken auf "Play" (Wiedergabe) wird das Spiel nahezu sofort gestartet, ohne zusätzliche Builds vornehmen zu müssen. "Pause" hält das Spiel an, und "Advance frame" (Langsamer Vorlauf) führt es einzelbildweise aus, wodurch Sie eine sehr genaue Debuggingkontrolle vornehmen können.
  6. Console (Konsole): Dieses Fenster kann etwas ausgeblendet sein, es zeigt jedoch die Ausgabe Ihrer Kompilierung, Fehler, Warnungen usw. an. Es zeigt auch Debugmeldungen vom Code, beispielsweise zeigt "Debug.Log" hier seine Ausgabe an.

Wichtig zu erwähnen, ist die Registerkarte "Game" (Spiel) neben der Registerkarte "Scene" (Szene). Diese Registerkarte wird aktiviert, wenn Sie auf "Play" (Wiedergabe) klicken und Ihr Spiel in diesem Fenster ausgeführt wird. Dies wird als Spielmodus bezeichnet. Hier erhalten Sie einen Playground für das Testen Ihres Spiels, wodurch Sie sogar sofortige Änderungen am Spiel vornehmen können, indem Sie zur Registerkarte "Scene" (Szene) zurückwechseln. Sie sollten hier dennoch Vorsicht walten lassen. Solange die Schaltfläche "Play" (Wiedergabe) markiert ist, befinden Sie sich im Wiedergabemodus, und wenn Sie ihn beenden, gehen alle von Ihnen im Wiedergabemodus vorgenommenen Änderungen verloren. Ich und nahezu jeder andere Unity-Entwickler, mit dem ich gesprochen habe, wurden auf diese Weise um die Früchte unserer Arbeit gebracht. Daher habe ich die Farbe meines Editors geöffnet, damit es offensichtlich ist, wann ich mich durch Auswahl der Optionen "Edit (Bearbeiten) | Preferences (Einstellungen) | Colors (Farben) | Playmode tint (Farbwert für Spielmodus)" im Bearbeitungsmodus befinde.

Informationen über Szenen

Alles, was in Ihrem Spiel ausgeführt wird, ist in einer Szene vorhanden. Wenn Sie Ihr Spiel für eine Plattform packen, ist das sich daraus ergebende Spiel eine Sammlung aus einer oder mehrerer Szenen sowie aus plattformabhängigen Code, den Sie hinzufügen. In einem Projekt können Sie über beliebig viele Szenen verfügen. Eine Szene kann man sich wie ein Level in einem Spiel vorstellen, obwohl Sie auch über mehrere Level in einer Szenendatei verfügen können, indem Sie einfach den Spieler bzw. die Kamera an verschiedene Punkte in der Szene verschieben. Beim Herunterladen von Drittanbieterpaketen oder sogar von Beispielspielen aus dem Asset Store müssen Sie für gewöhnlich nach den zu öffnenden Szenendateien in Ihrem Projekt suchen. Eine Szenendatei ist eine einzelne Datei, die alle Sorten der Metadaten über die Ressourcen enthält, die im Projekt für die aktuelle Szene und die zugehörigen Eigenschaften verwendet werden. Es ist wie bei jedem anderen Tool wichtig, eine Szene häufig während der Entwicklung durch Drücken auf die STRG-TASTE+S zu speichern.

Für gewöhnlich öffnet Unity die zuletzt von Ihnen bearbeitete Szene, auch wenn manchmal beim Öffnen von Unity ein Projekt geöffnet, bei dem eine neue leere Szene erstellt wird, was dazu führt, dass Sie die gewünschte Szene mithilfe des Projekt-Explorers suchen müssen. Für neue Benutzer kann dies ziemlich verwirrend sein. Es ist jedoch wichtig, daran zu denken, wenn Sie Ihr zuletzt bearbeitetes Projekt öffnen und sich fragen, wo Ihre Arbeiten sind! Entspannen Sie sich, Sie finden die Arbeit in einer in Ihrem Projekt gespeicherten Szenendatei. Sie können nach allen Szenen in Ihrem Projekt suchen, indem Sie auf das Symbol, was in Abbildung 4 hervorgehoben ist, klicken und den Filter auf "Scene" (Szene) anwenden.

Filtern von Szenen im Projekt
Abbildung 4 – Filtern von Szenen im Projekt

In einer Szene können Sie nichts ohne eine Kamera ansehen und nichts ohne eine Audio Listener-Komponente hören, die an einige "GameObject"-Elemente angefügt ist. Beachten Sie jedoch, dass Unity in jeder neuen Szene immer eine Kamera erstellt, die bereits eine Audio Listener-Komponente aufweist.

Projektstruktur und Importieren von Assets

Unity-Projekte sind nicht wie Visual Studio-Projekte. Sie öffnen keine Projektdatei oder Lösungsdatei, da es sie nicht gibt. Sie verweisen Unity auf eine Ordnerstruktur, und es öffnet den Ordner als ein Projekt. Projekte enthalten die Ordner "Assets", "Library", "ProjectSettings" und "Temp". Der einzige auf der Oberfläche angezeigte ist jedoch der Ordner "Assets" (siehe Abbildung 4).

Der Ordner "Assets" enthält alle Ihre Assets – Artwork, Code, Audioelemente. Jede einzelne Datei, die Sie in Ihr Projekt einfügen, wird hierhin verschoben. Dieser ist immer der Ordner auf oberster Ebene im Unity-Editor. Nehmen Sie jedoch nur Änderungen auf der Unity-Oberfläche, niemals jedoch durch das Dateisystem vor.

Der Ordner "Library" ist der lokale Zwischenspeicher für importierte Assets, er enthält alle Metadaten für die Assets. Im Ordner "ProjectSettings" werden die Einstellungen gespeichert, die Sie unter "Edit (Bearbeiten) | Project Settings (Projekteinstellungen)" konfigurieren. Der Ordner "Temp" wird während des Buildvorgangs für temporäre Dateien aus Mono und Unity verwendet.

Ich möchte nochmals erinnern, wie wichtig es ist, die Änderungen nur über die Unity-Oberfläche und nicht über das Dateisystem direkt vorzunehmen. Dazu zählen auch einfache Kopieren-und-Einfügen-Vorgänge. Unity verfolgt Metadaten für Ihre Objekte über den Editor nach. Daher sollten Sie den Editor verwenden, um Änderungen (mit Ausnahme weniger Grenzfälle) vorzunehmen. Sie können Elemente aus Ihrem Dateisystem problemlos per Drag-and-Drop in Unity ablegen.

Das äußerst wichtige "GameObject"

Praktisch alles in Ihrer Szene ist ein "GameObject". Denken Sie nur an "System.Object" in .NET Framework. Nahezu alle Typen werden daraus abgeleitet. Dasselbe Konzept gilt für "GameObject". Es ist die grundlegende Klasse für alle Objekte in Ihrer Unity-Szene. Sämtliche in Abbildung 5 (und viele weitere) gezeigte Objekte werden aus einem "GameObject" abgeleitet.

GameObjects in Unity
Abbildung 5 – "GameObjects" in Unity

Ein "GameObject" ist ziemlich einfach, da es zum Fenster "Inspector" (Prüfung) gehört. In Abbildung 6 können Sie sehen, dass der Szene ein leeres "GameObject" hinzugefügt wurde. Beachten Sie die entsprechenden Eigenschaften in "Inspector" (Prüfung). "GameObjects" weisen standardmäßig keine visuellen Eigenschaften auf. Einzig das Widget "Unity" wird angezeigt, wenn Sie das Objekt hervorheben. Zu diesem Zeitpunkt ist es einfach ein ziemlich leeres Objekt.

A - ein einfaches GameObject
Abbildung 6 A – ein einfaches "GameObject"

Ein "GameObject" verfügt über die Eigenschaften "Name", "Tag" (ähnelt einem Texttag, das Sie über ein "FrameworkElement.Tag" in XAML oder ein Tag in Windows Forms zuweisen würden), "Layer" und "Transform" (die wahrscheinlich wichtigste Eigenschaft von allen).

Bei der Eigenschaft "Transform" handelt es sich schlichtweg um die Position, Drehung und Skalierung eines beliebigen "GameObject". Unity verwendet das Koordinatensystem auf der linken Seite, in dem Sie sich die Koordinaten Ihres Computersystems als X (horizontal), Y (vertikal) und Z (Tiefe, d. h. was sich zum oder vom Bildschirm weg bewegt) vorstellen müssen.

Bei der Spielentwicklung ist die Verwendung von Vektoren nichts Ungewöhnliches, die ich in künftigen Artikeln ein wenig genauer abdecken werde. Zurzeit ist es ausreichend zu wissen, dass "Transform.Position" und "Transform.Scale" "Vector3"-Objekte sind. Ein "Vector3" ist einfach ein 3D-Vektor. Im Prinzip sind es nur drei Punkte: X, Y und Z. Mithilfe dieser drei einfachen Werte können Sie die Position eines Objekts festlegen und sogar ein Objekt in Richtung eines Vektors verschieben.

Komponenten

Durch das Hinzufügen von Komponenten können Sie "GameObjects" Funktionalitäten hinzufügen. Alles, was Sie hinzufügen, ist eine Komponente, und sie wird im Fenster "Inspector" (Prüfung) angezeigt. Es stehen "MeshRender"- und "SpriteRender"-Komponenten, Komponenten für die Audio- und Kamerafunktionalität, spielphysikbezogene Komponenten (Collider und starre Körper), Teilsysteme, Pfadfindungssysteme sowie benutzerdefinierte Drittanbieterkomponenten und vieles mehr zur Verfügung. Sie können eine Skriptkomponente verwenden, um Code zu einem Objekt zuzuweisen. Komponenten erwecken Ihre "GameObjects" zum Leben, indem Funktionalitäten hinzugefügt werden, die dem Muster "thedecorator" in der Softwareentwicklung ähneln, aber viel cooler sind.

Ich weise einem neuen "GameObject" etwas Code zu. In diesem Fall handelt es sich um einen einfachen Würfel, den Sie über die Optionen "GameObject | Create Other (Sonstiges erstellen) | Cube (Würfel)" erstellen können. Ich habe den Würfel in "Enemy" umbenannt und anschließend einen weiteren erstellt, um zwei Würfel zur Verfügung zu haben. In Abbildung 7 können Sie sehen, dass ich einen Würfel -15 Einheiten von der anderen verschoben habe, was mithilfe des Tools zum Verschieben auf der Symbolleiste möglich ist oder indem Sie auf die Taste W drücken, sobald ein Objekt hervorgehoben ist.

aktuelles Projekt mit zwei Würfeln
Abbildung 7 – aktuelles Projekt mit zwei Würfeln

Der Code ist eine einfache Klasse, die einen Spieler sucht und seinen Besitzer in diese Richtung bewegt. Für gewöhnlich nehmen Sie Bewegungsvorgänge mit einem der beiden Ansätze vor: Sie können ein Objekt entweder einzelbildweise zur neuen Position verschieben, indem Sie seine "Transform.Position"-Eigenschaften ändern, oder Sie können eine Physikkraft darauf anwenden und Unity den Rest der Aufgabe überlassen.

Für die Bearbeitung vom Typ "Jedes Einzelbild" ist eine etwas andere Denkweise erforderlich, als beim "Zu-diesem-Punkt-verschieben"-Ansatz. In diesem Beispiel verschiebe ich das Objekt ein wenig nach dem Muster "Jedes Einzelbild", sodass ich die genaue Kontrolle darüber habe, wohin es verschoben wird. Wenn Sie lieber nicht jedes Einzelbild anpassen möchten, stehen Ihnen Bibliotheken zum Vornehmen einer einzelnen Funktionsaufrufverschiebung zur Verfügung, wie dies beispielsweise bei der kostenlos erhältlichen iTween-Bibliothek der Fall ist.

Zunächst klicke ich mit der rechten Maustaste in das Fenster "Project" (Projekt), um ein neues Skript namens "EnemyAI" zu erstellen. Um dieses Skript zu einem Objekt zuzuweisen, ziehe ich die Skriptdatei einfach aus der Projektansicht zum Objekt in der Ansicht "Scene" (Szene) oder zur Hierarchie, und der Code wird zum Objekt zugewiesen. Unity übernimmt den Rest. So einfach ist das.

Abbildung 8 zeigt den "Enemy"-Würfel mit dem ihm zugewiesenen Skript.

Enemy mit dem ihm zugewiesenen Skript
Abbildung 8 – "Enemy" mit dem ihm zugewiesenen Skript

Sehen Sie sich den Code in Abbildung 9 an, und notieren Sie sich die öffentliche Variable. Wenn Sie in den Editor schauen, können Sie sehen, dass meine öffentliche Variable mit einer Option zum Überschreiben der Standardwerte zur Laufzeit angezeigt wird. Das ist ziemlich cool. Sie können Standardwerte in der GUI für einfache Typen ändern, und Sie können auch öffentliche Variablen (jedoch keine Eigenschaften) für viele verschieden Objekttypen verfügbar machen. Wenn ich diesen Code per Drag-and-Drop auf einem anderen "GameObject" ablege, wird eine von diese Codekomponente vollständig getrennte Instanz instanziiert. Dies ist ein grundlegendes Beispiel, und es kann, sagen wir, durch das Hinzufügen einer "RigidBody"-Komponenten zu diesem Objekt effizienter gemacht werden, aber ich halte es hier einfach.

Abbildung 9 – das "EnemyAI"-Skript

public class EnemyAI : MonoBehavior
{
  // These values will appear in the editor, full properties will not.
  public float Speed = 50;
  private Transform _playerTransform;
  private Transform _ myTransform;
  // Called on startup of the GameObject it's assigned to.
  void Start()
  {
    // Find some gameobject that has the text tag "Player" assigned to it.
    // This is startup code, shouldn't query the player object every
    // frame. Store a ref to it.
    var player = GameObject.FindGameObjectWithTag("Player");
    if (!player)
    {
      Debug.LogError(
        "Could not find the main player. Ensure it has the player tag set.");
    }
    else
    {
      // Grab a reference to its transform for use later (saves on managed
      // code to native code calls).
      _playerTransform = player.transform;
    }
    // Grab a reference to our transform for use later.
    _myTransform = this.transform;
  }
  // Called every frame. The frame rate varies every second.
  void Update()
  {
    // I am setting how fast I should move toward the "player"
    // per second. In Unity, one unit is a meter.
    // Time.deltaTime gives the amount of time since the last frame.
    // If you're running 60 FPS (frames per second) this is 1/60 = 0.0167,
    // so w/Speed=2 and frame rate of 60 FPS (frame rate always varies
     // per second), I have a movement amount of 2*0.0167 = .033 units
    // per frame. This is 2 units.
    var moveAmount = Speed * Time.deltaTime;
    // Update the position, move toward the player's position by moveAmount.
    _myTransform.position = Vector3.MoveTowards(_myTransform.position,
      _playerTransform.position, moveAmount);
  }
}

Im Code kann ich einen Verweis zu jeder im Editor verfügbar gemachten Komponente herstellen. Ich kann auch Skripts zu einem "GameObject" zuweisen, und zwar jedes mit seinen eigenen "Start"- und "Update"-Methoden (und vielen weiteren Methoden). Angenommen, für eine Skriptkomponente, die diesen Code enthält, ist ein Verweis zur Klasse "EnemyAI" (Komponente) erforderlich, so kann ich einfach nach dieser Komponente fragen:

public class EnemyHealth : MonoBehavior
private EnemyAI _enemyAI;
// Use this for initialization.
void Start () {
  // Get a ref to the EnemyAI script component on this game object.
  var enemyAI = this.GetComponent<EnemyAI>();
}
// Update is called once per frame.
void Update () {
  _enemyAI.MoveTowardsPlayer();
}

Nachdem Sie Code in MonoDevelop oder im Code-Editor Ihrer Wahl bearbeitet haben und anschließend zu Unity zurückwechseln, wird Ihnen für gewöhnlich eine kurze Verzögerung auffallen. Dies liegt daran, dass Unity im Hintergrund Ihren Code kompiliert. Sie können über die Optionen "Edit (Bearbeiten) | Preferences (Einstellungen) | External Tools (Externe Tools) | External Script Editor (Externer Skript-Editor)" Ihren Code-Editor (nicht den Debugger) ändern. Sämtliche Kompilierungsprobleme werden auf der Statusleiste ganz unten Ihres Unity-Editor-Bildschirms angezeigt, Sie sollten also ein Auge darauf haben. Wenn Sie versuchen, Ihr Spiel mit Fehlern im Code auszuführen, lässt Sie Unity den Vorgang nicht fortsetzen.

Schreiben von Code

Im vorherigen Codebeispiel gibt es die beiden Methoden "Start" und "Update", und die Klasse "EnemyHealth" erbt aus der Basisklasse "MonoBehavior", wodurch sie diese Klasse einfach zu einem "GameObject" zuweisen können. Es gibt jede Menge Funktionalitäten in dieser Basisklasse, die Sie verwenden, und für gewöhnlich ein paar Methoden und Eigenschaften. Die Hauptmethode sind jene, die Unity aufruft, wenn sie in Ihrer Klasse vorhanden sind. Es gibt eine Handvoll Methoden, die aufgerufen werden können (siehe bit.ly/1jeA3UM). Obwohl viele Methoden vorhanden sind, ebenso mit ASP.NET Web Forms-Seitenlebenszyklus, verwenden Sie für gewöhnlich nur einige davon. Im Folgenden finden Sie die häufigsten Codemethoden zum Implementieren in Ihre Klassen, die eine Beziehung zur Reihenfolge der Ereignisse für aus "MonoBehavior" abgeleiteten Klassen herstellen.

Awake: Diese Methode wird einmal pro Objekt aufgerufen, wenn das Objekt zum ersten Mal initialisiert wird. Andere Komponenten sind bis dato möglicherweise nicht initialisiert, daher wird diese Methode für gewöhnlich verwendet, um das aktuelle "GameObject" zu initialisieren. Sie sollten diese Methode immer verwenden, um eine aus "MonoBehavior" abgeleitete Klasse und nicht um einen Konstruktor zu initialisieren. Und versuchen Sie nicht, andere Objekte in Ihrer Szene hier abzufragen, da sie möglicherweise noch nicht initialisiert wurden.

Start: Diese Methode wird während des ersten Einzelbilds des Objektlebenszyklus, aber vor allen anderen "Update"-Methoden aufgerufen. "Start" mag "Awake" zwar ähneln, aber mit "Start" wissen Sie, dass die anderen Objekte über "Awake" initialisiert wurden und in Ihrer Szene vorhanden sind. Daher können Sie andere Objekte wie folgt auf einfache Weise in Code abfragen:

// Returns the first EnemyAI script component instance it finds on any game object.
// This type is EnemyAI (a component), not a GameObject.
var enemyAI = GameObject.FindObjectOfType<EnemyAI>();
// I'll actually get a ref to its top-level GameObject.
var enemyGameObject = enemyAI.gameObject;
// Want the enemy’s position?
var position = enemyGameObject.transform.position;

Aktualisierung: Diese Methode wird als "Jedes Einzelbild" bezeichnet. Wie oft erfolgt dies, fragen Sie? Nun, das ist unterschiedlich. Dies ist vollständig von der Berechnung abhängig. Da Ihr System die eigene Auslastung immer ändert, wenn es unterschiedliche Dinge rendert, variiert diese Einzelbildrate jede Sekunde. Sie können auf die Schaltfläche "Stats" (Statistiken) auf der Registerkarte "Game" (Spiel) drücken, wenn Sie in den Spielmodus wechseln, um Ihre aktuelle Einzelbildrate anzuzeigen (siehe Abbildung 10).

Abrufen von Statistiken
Abbildung 10 – Abrufen von Statistiken

FixedUpdate: Diese Methode wird unabhängig von der Einzelbildrate in einer festen Häufigkeit pro Sekunde aufgerufen. Da "Update" pro Sekunde in einer variierenden Häufigkeit aufgerufen wird und mit der Physik-Engine nicht synchron ist, empfiehlt es sich für gewöhnlich, "FixedUpdate" zu verwenden, wenn Sie eine Erzwingung oder einige andere mit der Physik in Zusammenhang stehende Funktionen für ein Objekt bereitstellen möchten. "FixedUpdate" wird standardmäßig alle 0,02 Sekunden aufgerufen. Unity führt demnach alle 0,02 Sekunden (dieses Intervall wird als fester Zeitschritt bezeichnet und kann vom Entwickler angepasst werden) ebenfalls Physikberechnungen aus, was abermals von der Einzelbildrate unabhängig ist.

Unity-generierte Codeprojekte

Sobald Ihr Projekt Code aufweist, erstellt Unity mindestens eine Projektdatei in Ihrem Stammordner (der auf der Unity-Oberfläche nicht sichtbar ist). Hierbei handelt es sich nicht um die Unity-Modulbinärdateien, sondern um die Projekte für Visual Studio oder MonoDevelop, in denen Sie Ihren Code bearbeiten und kompilieren können. Unity kann das erstellen, was den Anschein vieler getrennter Projekte (siehe Abbildung 11) hat, obwohl jedes einzelne einen wichtigen Zweck hat.

In Unity erstellte Projekte
Abbildung 11 – In Unity erstellte Projekte

Wenn Sie über ein einfaches Unity-Projekt verfügen können Sie nicht alle diese Dateien anzeigen. Sie werden nur erstellt, wenn Sie in verschiedene spezielle Ordner Code einfügen. Die in Abbildung 11 gezeigten Objekte werden durch nur drei Typen aufgeteilt:

  • Assembly-CSharp.csproj
  • Assembly-CSharp-Editor.csproj
  • Assembly-CSharp-firstpass.csproj

Für jedes dieser Projekte wird ein Duplikatprojekt mit der "-vs"-Anfügung (beispielsweise "Assembly-CSharp-vs.csproj") erstellt. Diese Projekte werden verwendet, wenn Visual Studio Ihr Code-Editor ist, und sie können Ihrem exportierten Projekt aus Unity für das plattformspezifische Debugging in Ihrer Visual Studio-Lösung hinzugefügt werden.

Die anderen Projekte erfüllen den gleichen Zweck, in ihnen ist jedoch "UnityScript" anstelle von "CSharp" vorhanden. Hierbei handelt es sich einfach um die JavaScript-Versionen (UnityScript) der Projekte, die nur vorhanden sind, wenn Sie JavaScript in Ihrem Unity-Spiel verwenden, und auch nur dann, wenn Ihre Skripts in den Ordnern vorhanden sind, die das Erstellen dieser Projekte auslösen.

Da Sie nun gesehen haben, was für Projekte erstellt werden, untersuche ich die Ordner, die diese Projekte auslösen, und ich zeige Ihnen ihren Zweck. Jeder Ordnerpfad nimmt an, er befände sich unter dem Stammordner "/Assets" in Ihrer Projektansicht. "Assets" ist immer der Stammordner. Er enthält sämtliche Ihrer darunter liegenden Asset-Dateien. Beispielsweise ist "Standard Assets" eigentlich "/Assets/Standard Assets". Der Buildvorgang für Ihre Skripts durchläuft vier Phasen zum Generieren von Assemblys. In Phase 1 kompilierte Objekte können die in Phase 2 nicht sehen, da sie noch nicht kompiliert wurden. Das ist wichtig zu wissen, wenn Sie UnityScript und C# im selben Projekt kombinieren. Wenn Sie auf eine C#-Klasse aus UnityScript verweisen möchten, müssen Sie die Kompilierung in einer früheren Phase gewährleisten.

Phase 1 besteht aus Laufzeitskripts in den Ordnern "Standard Assets", "Pro Standard Assets" und "Plug-ins", die sich allesamt unter "/Assets" befinden. In dieser Phase wird das Projekt "Assembly-CSharp-firstpass.csproj" erstellt.

Phase 2-Skripts befinden sich in den Ordnern "Standard Assets/Editor", "Pro Standard Assets/Editor" und "Plug-ins/Editor". Der letzte Ordner ist für Skripts gedacht, die mit der Unity-Editor-API für die Entwurfszeitfunktionalität (stellen Sie sich ein Visual Studio-Plug-In vor und wie es die GUI erweitert; nur dieses kann im Unity-Editor ausgeführt werden) interagieren. In dieser Phase wird das Projekt "Assembly-CSharp-Editor-firstpass.csproj" erstellt.

Phase 3 subsumierte alle anderen Skripts, die nicht im Ordner "Editor" enthalten sind. In dieser Phase wird das Projekt "Assembly-CSharp-Editor.csproj" erstellt.

Phase 4 besteht aus allen verbleibenden Skripts (jene, die sich in jedem anderen Ordner namens "Editor" befinden, wie beispielsweise "/Assets/Editor oder /Assets/­Foo/Editor"). In dieser Phase wird das Projekt "Assembly-CSharp.csproj" erstellt.

Es gibt auch einige seltener verwendete Ordner, die hier nicht erläutert werden, wie etwa "Resources". Und es gibt die noch nicht beantwortete Frage, was der Compiler verwendet. .NET? Mono? .NET für die Windows-Runtime (WinRT)? .NET für die Windows-Phone-Laufzeit? Abbildung12 veranschaulicht die für die Kompilierung verwendeten Standardwerte. Das ist wichtig zu wissen, besonders für WinRT-basierte Anwendungen, da die pro Plattform verfügbaren APIs variieren.

Abbildung 12 – Kompilierungsvariationen

Plattform Generierung der Spielassemblys erfolgt durch Abschließende Kompilierung erfolgt durch
Windows Phone 8 Mono (möglicherweise in englischer Sprache) Visual Studio/.NET
Windows Store .NET Visual Studio/.NET (WinRT)
Eigenständige ausführbare Windows-Datei (.exe) Mono (möglicherweise in englischer Sprache) Unity – generiert EXE-Dateien und Bibliotheken
Windows Phone 8,1 .NET Visual Studio/.NET (WinRT)

Wenn Sie einen Build für Windows ausführen, ist Unity für das Vornehmen der Aufrufe verantwortlich, um die Spielbibliotheken aus Ihrem "C#/UnityScript/Boo"-Code (DLL-Dateien) zu generieren und die entsprechenden systemeigenen Laufzeitbibliotheken einzubeziehen. Für Windows Store und Windows Phone 8 exportiert es eine Visual Studio-Lösung, jedoch mit Ausnahme für eigenständige ausführbare Windows-Dateien. In diesem Fall generiert Unity die EXE- und die erforderlichen DLL-Dateien. Die verschiedenen Buildtypen werde ich im abschließenden Artikel dieser Reihe erläutern, wenn ich mich in Bezug auf die Plattformerstellung äußere. Das Grafik-Rendering auf niedriger Ebene wird auf den Windows-Plattformen mithilfe von DirectX vorgenommen.

Das Entwerfen eines Spiels in Unity ist ein ziemlich einfaches Verfahren:

  • Bringen Sie Ihre Assets (Artwork, Audio usw.) ein. Nutzen Sie den Asset Store. Schreiben Sie Ihren eigenen. Stellen Sie einen Künstler ein. Beachten Sie, dass Unity eine systemeigene Unterstützung für Maya, Cheetah3d, Blender und 3dsMax bietet. In einigen Fällen muss Software mit diesen systemeigenen 3D-Formaten installiert werden, damit sie funktioniert. Und es funktioniert auch mit den allgemeinen OBJ- und FBX-Dateiformaten.
  • Schreiben Sie Code in C#, JavaScript/UnityScript oder Boo zum Steuern Ihrer Objekte, Szenen und zum Implementieren von Spiellogik.
  • Testen Sie in Unity. Exportieren Sie in eine Plattform.
  • Testen Sie auf dieser Plattform. Nehmen Sie die Bereitstellung vor.

Doch warten Sie, ich möchte mehr!

Dieser Artikel dient als eine Übersicht über die Architektur und den Vorgang in Unity. Ich habe die Oberfläche, Grundlagen in Bezug auf das Zuweisen von Code, "GameObjects", Komponenten, Mono, .NET usw. behandelt, was eine gute Grundlage für den nächsten Artikel sein sollte, in dem ich das Assemblieren von Spielkomponenten für ein 2D-Spiel näher betrachten werde. Schauen Sie bei Gelegenheit bei der Microsoft Virtual Academy vorbei, da ich eine zweitägige Unity-Lernveranstaltung im Spätsommer durchführen werde. Und halten Sie unter unity3d.com/pages/windows/events Ausschau nach regionalen Lernveranstaltungen.


Adam Tuliper arbeitet bei Microsoft als Senior Technical Evangelist und lebt im sonnigen Kalifornien. Er ist Entwickler für Indie Games, Co-Administrator beim Orange County Unity Meetup und Autor auf pluralsight.com. Seine Frau und er werden bald ihr drittes Kind bekommen, Sie können ihn dennoch in einer freien Minute unter adamt@microsoft.com oder auf Twitter unter twitter.com/AdamTuliper erreichen.

Unser Dank gilt den folgenden technischen Experten für die Durchsicht dieses Artikels: Matt Newman (Subscience Studios), Jaime Rodriguez (Microsoft) und Tautvydas Žilys (Unity)