Verwalten des Status und der Ereignisse zwischen Komponenten in GameObject

Verwalten des Status und der Ereignisse zwischen Komponenten in GameObject


Link zum Projekt

Wie jeder weiß, der mehr oder weniger mit der Unity-Plattform vertraut ist, besteht jedes GameObject -Spielobjekt aus Komponenten (integriert oder benutzerdefiniert, was normalerweise als „Skript“ bezeichnet wird). Komponenten erben von der Basisklasse MonoBehavior .



Und normalerweise wird gut oder oft eine direkte Verbindung hergestellt, um die Komponenten zu binden.



Das heißt, Um in einer Komponente Daten von einer anderen Komponente abzurufen , erhalten wir diese mithilfe der GetComponent <...> () -Methode, beispielsweise wie folgt :



In diesem Beispiel wird ein Verweis auf eine Komponente vom Typ SomeComponent in die Variable someComponent eingefügt .

Bei diesem „eng gekoppelten“ Ansatz ist es insbesondere bei einer großen Anzahl von Komponenten recht leicht, verwirrt zu werden und die Integrität einer solchen Verbindung aufrechtzuerhalten. Wenn sich beispielsweise der Name einer Eigenschaft oder Methode in einer Komponente ändert, müssen Sie ihn in allen Komponenten korrigieren, die dies verwenden. Und das ist eine Blutung.

Unter dem Schnitt viele Bilder

Erstellen einer Lösung basierend auf der „starken Verbundenheit“ von Komponenten


Wir werden ein leeres Projekt erstellen, um die übliche Situation zu reproduzieren, wenn wir bestimmte Komponenten haben und jede auf einander verweist, um Daten zu empfangen oder zu steuern.



Ich habe zwei Skripte hinzugefügt, FirstComponent und SecondComponent , die als Komponenten im Spielobjekt verwendet werden:



Jetzt werde ich für jede der für die Experimente benötigten Komponenten eine einfache Struktur definieren.





Stellen Sie sich nun eine Situation vor, in der wir die Feldwerte state1 von der FirstComponent- Komponente abrufen und ihre ChangeState (...) -Methode in der SecondComponent- Komponente aufrufen müssten . Dazu müssen Sie einen Link zur Komponente erhalten und die erforderlichen Daten in der SecondComponent- Komponente anfordern :



Nachdem wir das Spiel in der Konsole gestartet haben, werden wir sehen, dass wir Daten von FisrtComponent von SecondComponent erhalten und den Status der ersten geändert haben



Genauso können wir jetzt die Daten und in entgegengesetzter Richtung von der FirstComponent- Komponente abrufen, um die Daten der SecondComponent- Komponente abzurufen .



Nach dem Start des Spiels wird auch sichtbar, dass wir Daten empfangen und die SecondComponent- Komponente von FirstComponent aus steuern können .



Dies war ein ziemlich einfaches Beispiel, und um zu verstehen, welche Art von Problem ich beschreiben möchte, wäre es notwendig, die Struktur und die Beziehungen aller Komponenten stark zu komplizieren, aber die Bedeutung ist klar. Nun ist die Verbindung zwischen den Komponenten wie folgt:





Das Erweitern eines Spielobjekts mit neuen Komponenten, wenn diese mit vorhandenen interagieren müssen, ist eher Routine. Und insbesondere, wenn sich beispielsweise der Name des Felds state1 in der FirstComponent- Komponente beispielsweise in state_1 ändert und Sie den Namen ändern müssen, in dem er in allen Komponenten verwendet wird. Oder wenn die Komponente zu viele Felder hat, wird es ziemlich schwierig, sie zu navigieren.

Erstellen einer Lösung basierend auf dem „allgemeinen Status“ zwischen Komponenten


Stellen Sie sich nun vor, wir müssten nicht einen Link zu jeder interessierenden Komponente erstellen und Daten daraus abrufen, sondern es würde ein bestimmtes Objekt geben, das die Zustände und Daten aller Komponenten im Spielobjekt enthält. Im Diagramm würde es so aussehen:



Allgemeiner Status oder Allgemeines Statusobjekt (SharedState) ist auch eine Komponente, die die Rolle einer Dienstkomponente spielt und den Status aller Komponenten des Spielobjekts speichert.

Ich werde eine neue Komponente erstellen und sie SharedState nennen:



Und ich werde den Code für diese universelle Komponente bestimmen. Es speichert ein geschlossenes Wörterbuch und einen Indexer für eine bequemere Arbeit mit dem Komponentenwörterbuch, es ist auch eine Kapselung und es funktioniert nicht direkt mit dem Wörterbuch anderer Komponenten.



Jetzt muss diese Komponente auf dem Spielobjekt platziert werden, damit die anderen Komponenten darauf zugreifen können:



Als Nächstes müssen Sie einige Änderungen an den Komponenten FirstComponent und SecondComponent vornehmen , damit sie die SharedState- Komponente zum Speichern ihres Status oder ihrer Daten verwenden:





Wie Sie dem Komponentencode entnehmen können, speichern wir das Feld nicht mehr, sondern verwenden den allgemeinen Status und haben über den Schlüssel "state1" oder "counter" Zugriff auf seine Daten. Jetzt sind diese Daten an keine Komponente gebunden. Wenn eine dritte Komponente angezeigt wird und auf SharedState zugreifen kann, kann er auf alle diese Daten zugreifen.

Um die Funktionsweise dieses Schemas zu demonstrieren, müssen Sie die Aktualisierungsmethoden in beiden Komponenten ändern. In FisrtComponent :



Und in der SecondComponent- Komponente:



Jetzt kennen die Komponenten den Ursprung dieser Werte nicht, dh bevor sie sich an eine bestimmte Komponente gewandt haben, um sie abzurufen. Jetzt werden sie einfach in einem gemeinsamen Raum gespeichert und jede Komponente hat Zugriff auf sie.

Nach dem Start des Spiels können Sie sehen, dass die Komponenten die gewünschten Werte erhalten:



Nachdem wir nun wissen, wie es funktioniert, können wir die Basisinfrastruktur für den Zugriff auf den allgemeinen Status in der Basisklasse ableiten, um nicht alles in jeder Komponente einzeln auszuführen:



Und ich werde es abstrakt machen, damit ich nicht versehentlich eine Instanz davon erstelle ... Und es ist auch ratsam, ein Attribut hinzuzufügen, das angibt, dass für diese Basiskomponente die SharedState- Komponente erforderlich ist:



Jetzt müssen Sie die Komponenten FirstComponent und SecondComponent so ändern , dass sie von SharedStateComponent erben und alle unnötigen Elemente entfernen:





Ok Was ist mit Methoden aufrufen? Es wird vorgeschlagen, dies auch nicht direkt, sondern über das Publisher-Subscriber-Muster zu tun. Vereinfacht.

Um dies zu implementieren, müssen Sie eine weitere allgemeine Komponente hinzufügen, ähnlich der, die die Daten enthält, mit der Ausnahme, dass diese nur Abonnements enthält und SharedEvents heißt:



Das Prinzip ist wie folgt. Eine Komponente, die eine Methode für eine andere Komponente aufrufen möchte, führt dies nicht direkt aus, sondern durch Aufrufen eines Ereignisses, nur nach Namen, wenn Daten aus dem allgemeinen Status abgerufen werden.

Jede Komponente abonniert einige Ereignisse, die sie verfolgen kann. Und wenn er dieses Ereignis abfängt, führt er den Handler aus, der in der Komponente selbst definiert ist.
Erstellen Sie die SharedEvents- Komponente:



Außerdem definieren wir die Struktur, die für die Verwaltung von Abonnements und Veröffentlichungen erforderlich ist.



Für den Datenaustausch zwischen Abonnements, Veröffentlichungen wird eine Basisklasse definiert, eine spezifische für den Autor jeder Veranstaltung unabhängig festgelegt und anschließend mehrere Beispiele definiert:



Jetzt müssen Sie dem Spielobjekt eine neue Komponente hinzufügen:



Erweitern Sie die SharedStateComponent- Basisklasse ein wenig und fügen Sie die Anforderung hinzu, dass das Objekt SharedEvents enthält



Neben dem allgemeinen Statusobjekt muss das allgemeine Abonnementobjekt aus dem Spielobjekt abgerufen werden:





Jetzt definieren wir ein Ereignisabonnement, das wir in FisrtComponent verarbeiten, und eine Klasse zum Übertragen von Daten über diesen Ereignistyp. Außerdem ändern wir SecondComponent so, dass das Ereignis für dieses Abonnement veröffentlicht wird:





Jetzt haben wir jedes Ereignis namens "writedomedata" in der FirstComponent- Komponente abonniert und drucken einfach eine Nachricht an die Konsole, wenn sie auftritt. In diesem Beispiel wird die Veröffentlichung eines Ereignisses mit dem Namen "writeomedataata" in der SecondComponent- Komponente aufgerufen und einige Informationen übertragen, die in der Komponente verwendet werden können, die Ereignisse mit diesem Namen abfängt .

Nachdem wir das Spiel in 5 Sekunden gestartet haben, sehen wir das Ergebnis der Verarbeitung des Ereignisses in FirstComponent :



Zusammenfassung


Wenn Sie nun die Komponenten dieses Spielobjekts erweitern müssen, das auch den allgemeinen Status und die allgemeinen Ereignisse verwendet, müssen Sie eine Klasse hinzufügen und einfach von SharedStateComponent erben:



Fortsetzung des Themas

Source: https://habr.com/ru/post/de438554/


All Articles