Die Implementierung gängiger Entwurfsmuster für die Spieleprogrammierung in Ihrem Unity-Projekt kann Ihnen dabei helfen, eine saubere, organisierte und lesbare Codebasis effizient zu erstellen und zu pflegen. Design Patterns verkürzen die Refactoring- und Testzeit, beschleunigen die Entwicklungsprozesse und tragen zu einer soliden Grundlage für das Wachstum Ihres Spiels, Teams und Unternehmens bei.
Betrachten Sie Entwurfsmuster nicht als fertige Lösungen, die Sie kopieren und in Ihren Code einfügen können, sondern als zusätzliche Werkzeuge, die Ihnen bei der Entwicklung größerer, skalierbarer Anwendungen helfen können.
Auf dieser Seite werden die Entwurfsmuster Model View Controller (MVC) und Model View Presenter (MVP) erläutert.
Der Inhalt hier basiert auf dem kostenlosen E-Book, Verbessern Sie Ihren Code mit Programmiermustern für Spiele.
Weitere Artikel aus der Reihe Unity Design Patterns für die Spieleprogrammierung finden Sie im Unity Best Practices Hub oder über diese Links:
Mit den Entwurfsmustern Model-View-Controller (MVC) und Model-View-Presenter (MVP) können Sie die Daten und die Logik in Ihrer Anwendung von deren Darstellung trennen. Diese Muster wenden die Prinzipien der "Trennung von Belangen" an, die die Flexibilität und Wartbarkeit Ihrer Codebasis verbessern können.
Bei der Entwicklung von Unity-Spielen können Sie diese Muster verwenden, um die Logik eines Spiels in verschiedene Komponenten aufzuteilen, z. B. die Daten (Modell), die visuelle Darstellung (Ansicht) und die Logik, die die Interaktion zwischen den beiden steuert (Controller oder Presenter).
MVC ist eine Familie von Entwurfsmustern, die häufig bei der Entwicklung von Benutzeroberflächen in Softwareanwendungen verwendet werden.
Die allgemeine Idee hinter MVC ist, den logischen Teil Ihrer Software von den Daten und der Präsentation zu trennen. Dies trägt dazu bei, unnötige Abhängigkeiten zu verringern und möglicherweise Spaghetti-Code zu reduzieren.
Wie der Name schon sagt, unterteilt das MVC-Muster Ihre Anwendung in drei Schichten:
Das Modell speichert Daten: Das Modell ist ein reiner Datencontainer, der Werte enthält. Es führt keine Spiellogik oder Berechnungen aus.
Die Ansicht ist die Schnittstelle: Die Ansicht formatiert und rendert eine grafische Darstellung Ihrer Daten auf dem Bildschirm.
Der Controller übernimmt die Logik: Stellen Sie sich dies als das Gehirn vor. Es verarbeitet die Spieldaten und berechnet, wie sich die Werte zur Laufzeit ändern.
Durch diese Trennung wird auch genau festgelegt, wie diese drei Teile miteinander interagieren. Das Modell verwaltet die Anwendungsdaten, während die Ansicht diese Daten für den Benutzer anzeigt. Der Controller verarbeitet die Eingaben und führt alle Entscheidungen oder Berechnungen der Spieldaten durch. Dann sendet es die Ergebnisse an das Modell zurück.
Der Controller enthält selbst keine Spieldaten. Auch nicht die Ansicht. Das MVC-Design schränkt die Aufgaben der einzelnen Schichten ein. Ein Teil enthält die Daten, ein anderer Teil verarbeitet die Daten, und der letzte Teil zeigt die Daten dem Benutzer an.
Oberflächlich betrachtet kann man dies als eine Erweiterung des Prinzips der Alleinverantwortung betrachten. Jeder Teil macht nur eine Sache, und das ist der entscheidende Vorteil der MVC-Architektur.
Bei der Entwicklung eines Unity-Projekts mit MVC fungiert das vorhandene UI-Framework (entweder das UI Toolkit oder Unity UI) natürlich als View. Da die Engine eine vollständige Implementierung der Benutzeroberfläche bietet, müssen Sie keine einzelnen Komponenten der Benutzeroberfläche von Grund auf neu entwickeln.
Würde man jedoch dem traditionellen MVC-Muster folgen, müsste der View-spezifische Code zur Laufzeit auf Änderungen in den Daten des Models warten.
Obwohl dies ein gültiger Ansatz ist, entscheiden sich viele Unity-Entwickler für eine MVC-Variante, bei der der Controller als Vermittler fungiert. Hier beobachtet die Ansicht das Modell nicht direkt. Stattdessen funktioniert es ähnlich wie in der obigen Abbildung.
Diese MVC-Variante wird als Model-View-Presenter-Design (MVP) bezeichnet. MVP bewahrt die Trennung der Bereiche mit drei verschiedenen Anwendungsschichten. Die Zuständigkeiten der einzelnen Teile ändern sich jedoch leicht.
In MVP fungiert der Presenter (in MVC Controller genannt) als Vermittler für die anderen Schichten. Sie ruft Daten aus dem Modell ab und formatiert sie dann für die Anzeige in der Ansicht. MVP schaltet um, welche Ebene die Eingaben verarbeitet. Nicht der Controller, sondern die View ist für die Bearbeitung von Benutzereingaben zuständig.
Beachten Sie, wie Ereignisse und das Beobachtermuster in diesen Entwurf einfließen. Der Benutzer kann mit den Komponenten Button, Toggle und Slider von Unity UI interagieren. Die Ansichtsschicht sendet diese Eingaben über UI-Ereignisse an den Präsentator zurück, der wiederum das Modell bearbeitet. Ein Zustandsänderungsereignis des Modells teilt dem Präsentator mit, dass die Daten aktualisiert wurden. Der Presenter übergibt die geänderten Daten an die Ansicht, die die Benutzeroberfläche aktualisiert.
Auf Github steht ein Beispielprojekt zur Verfügung, das verschiedene Programmiermuster demonstriert, darunter ein Beispiel für die Implementierung einer Variante des MVP.
Das MVP-Beispiel besteht aus einem einfachen System, das den Gesundheitszustand einer Figur oder eines Gegenstands anzeigt. In diesem Beispiel befindet sich alles in einer Klasse, in der Daten und Benutzeroberfläche gemischt sind, aber das würde in der Praxis nicht gut funktionieren. Das Hinzufügen weiterer Funktionen würde komplizierter werden, da man sie erweitern muss. Außerdem würde das Testen und Refactoring eine Menge Overhead verursachen.
Stattdessen können Sie Ihre Gesundheitskomponenten auf eine MVP-gerechtere Art und Weise umschreiben, indem Sie Ihre Skripte in einen Health und HealthPresenter aufteilen.
Im Beispielprojekt können Sie auf das Zielobjekt klicken, das durch eine schießende Scheibe dargestellt wird(ClickDamage.cs), um es zu beschädigen, oder die Gesundheit mit der Schaltfläche zurücksetzen. Diese Ereignisse informieren den HealthPresenter (der den Schaden oder das Zurücksetzen aufruft), anstatt den Gesundheitszustand direkt zu ändern. Der UI-Text und der UI-Schieberegler werden aktualisiert, wenn die Gesundheit ein Ereignis auslöst und dem HealthPresenter mitteilt, dass sich seine Werte geändert haben.
Lassen Sie uns näher darauf eingehen, wie eine Gesundheitskomponente aussehen könnte. In dieser Version dient die Gesundheit als Modell. Es speichert den aktuellen Gesundheitszustand und ruft bei jeder Änderung dieses Werts das Ereignis " HealthChanged" auf. Health enthält keine Spiellogik, sondern nur Methoden zum Inkrementieren und Dekrementieren der Daten.
Dies ermöglicht eine klare Unterscheidung zwischen den Daten, der Art ihrer Darstellung und der Art ihrer Kontrolle.
MVP (und MVC) eignen sich besonders gut für größere und UI-lastige Softwareanwendungen, sind aber nicht auf diese Anwendungsfälle beschränkt. Wenn die Entwicklung Ihres Spiels ein großes Team erfordert und Sie davon ausgehen, dass Sie es nach der Markteinführung noch lange Zeit betreuen werden, könnten Sie die folgenden Vorteile sehen:
Reibungslose Arbeitsteilung: Da Sie die Ansicht vom Presenter getrennt haben, kann die Entwicklung und Aktualisierung Ihrer Benutzeroberfläche fast unabhängig vom Rest der Codebasis erfolgen. Haben Sie erfahrene Front-End-Entwickler in Ihrem Team? Sie sollen sich um die Ansicht kümmern.
Vereinfachte Unit-Tests mit MVP und MVC: Diese Entwurfsmuster trennen die Spiellogik von der Benutzeroberfläche. So können Sie Objekte simulieren, um mit Ihrem Code zu arbeiten, ohne den Abspielmodus im Editor aufrufen zu müssen. Dies kann eine erhebliche Zeitersparnis bedeuten.
Lesbarer Code, der gewartet werden kann: Mit diesem Entwurfsmuster neigen Sie dazu, kleinere Klassen zu erstellen, was sie leichter lesbar macht. Weniger Abhängigkeiten bedeuten in der Regel weniger Stellen, an denen Ihre Software versagen kann, weniger Stellen, an denen sich Fehler verstecken könnten, und einfachere Tests.
Obwohl MVC und MVP in der Webentwicklung oder bei Unternehmenssoftware weit verbreitet sind, werden die Vorteile oft erst dann deutlich, wenn Ihre Anwendung eine ausreichende Größe und Komplexität erreicht hat. Bevor Sie eines der beiden Muster in Ihrem Unity-Projekt implementieren, müssen Sie Folgendes beachten:
Sie müssen im Voraus planen: MVC und MVP sind größere Architekturmuster. Um eine davon zu verwenden, müssen Sie Ihre Klassen nach Zuständigkeiten aufteilen, was eine gewisse Organisation und mehr Arbeit im Vorfeld erfordert. Design Patterns lassen sich am besten konsistent anwenden, daher sollten Sie eine Praxis für die Organisation Ihrer Benutzeroberfläche einführen und sicherstellen, dass Ihr Team mitzieht.
Nicht alles in Ihrem Unity-Projekt wird dem Muster entsprechen: In einer "reinen" MVC- oder MVP-Implementierung ist alles, was auf dem Bildschirm dargestellt wird, wirklich Teil der Ansicht. Nicht jede Unity-Komponente lässt sich einfach in Daten, Logik und Schnittstelle aufteilen (z. B. ein MeshRenderer). Außerdem bringen einfache Skripte möglicherweise nicht viele Vorteile von MVC/MVP.
Sie müssen einschätzen, wo Sie am meisten von dem Muster profitieren können. Normalerweise können Sie sich von den Unit-Tests leiten lassen. Wenn MVC/MVP das Testen erleichtern können, sollten Sie sie für diesen Aspekt der Anwendung in Betracht ziehen. Andernfalls sollten Sie nicht versuchen, das Muster auf Ihr Projekt zu übertragen.
Viele weitere Tipps zur Verwendung von Entwurfsmustern in Ihren Unity-Anwendungen sowie die SOLID-Prinzipien finden Sie in dem kostenlosen E-Book Verbessern Sie Ihren Code mit Programmiermustern für Spiele.
Wenn Sie eine ausführlichere Anleitung zur Verwendung von Unity UI und UI Toolkit wünschen, lesen Sie bitte das ausführliche Handbuch, User Interface Design und Implementierung in Unity das von UI-Experten geschrieben wurde.
Alle fortgeschrittenen technischen E-Books und Artikel zu Unity finden Sie im Best Practices Hub. Die E-Books sind auch auf der Seite mit den fortgeschrittenen bewährten Verfahren in der Dokumentation verfügbar.