In einem
frĂŒheren Artikel habe ich die Technologien und AnsĂ€tze beschrieben, die wir bei der Entwicklung eines neuen mobilen, schnellen Shooters verwenden. Weil Es war eine Rezension und sogar ein oberflĂ€chlicher Artikel - heute werde ich tiefer gehen und detailliert erklĂ€ren, warum wir beschlossen haben, unser eigenes ECS-Framework zu schreiben und die vorhandenen nicht verwendet haben. Am Ende gibt es Codebeispiele und einen kleinen Bonus.

Was ist ECS als Beispiel?
Ich habe bereits kurz beschrieben, was Entity Component System ist, und es gibt Artikel auf HabrĂ© ĂŒber ECS (im Grunde genommen jedoch Ăbersetzungen von Artikeln - siehe meine Rezension der interessantesten davon am Ende des Artikels als Bonus). Und heute werde ich Ihnen anhand unseres Codebeispiels erklĂ€ren, wie wir ECS verwenden.
Das obige Diagramm beschreibt die Essenz des
Players , seine Komponenten und deren Daten sowie die Systeme, die mit dem Player und seinen Komponenten arbeiten. Das Hauptobjekt im Diagramm ist der Spieler:
- kann sich im Raum bewegen - Transformations- und Bewegungskomponenten , MoveSystem ;
- hat etwas Gesundheit und kann sterben - Komponente Gesundheit , Schaden , DamageSystem ;
- nach dem Tod erscheint am Respawn-Punkt - die Transformationskomponente fĂŒr die Position, das RespawnSystem ;
- kann unverwundbar sein - Komponente unbesiegbar .
Wir beschreiben dies mit einem Code. Lassen Sie uns zunĂ€chst Schnittstellen fĂŒr Komponenten und Systeme erhalten. Komponenten können gemeinsame Hilfsmethoden haben, das System hat nur eine
Execute- Methode, die den Zustand der Welt am Eingang zur Verarbeitung empfÀngt:
public interface IComponent {
FĂŒr Komponenten erstellen wir Stub-Klassen, die von unserem Codegenerator verwendet werden, um sie in tatsĂ€chlich verwendeten Komponentencode zu konvertieren. Lassen Sie uns ein paar Leerzeichen fĂŒr
Gesundheit ,
Schaden und
Unbesiegbar bekommen (fĂŒr den Rest der Komponenten wird es Ă€hnlich sein).
[Component] public class Health { [Max(1000)]
Komponenten bestimmen den Zustand der Welt, daher enthalten sie nur Daten ohne Methoden. Gleichzeitig enthÀlt
Invincible keine Daten. Sie werden in der Logik als Zeichen der Unverwundbarkeit verwendet. Wenn die Essenz des Spielers diese Komponente enthÀlt, ist der Spieler jetzt unverwundbar.
Das
Component- Attribut wird vom Generator verwendet, um die leeren Klassen fĂŒr die Komponenten zu finden. Die
Attribute Max und
DontSend werden als Hinweise fĂŒr die Serialisierung und Reduzierung der GröĂe des Status der Welt benötigt, der ĂŒber das Netzwerk ĂŒbertragen oder auf der Festplatte gespeichert wird. In diesem Fall serialisiert der Server das Feld
Betrag nicht und sendet es ĂŒber das Netzwerk (da Clients diesen Parameter nicht verwenden, wird er nur auf dem Server benötigt). Und das
HP- Feld kann angesichts des maximalen Gesundheitswerts gut in mehrere Bits gepackt werden.
Wir haben auch eine
vorgefertigte EntitĂ€tsklasse , in der wir Informationen zu allen möglichen Komponenten einer EntitĂ€t hinzufĂŒgen, und der Generator erstellt bereits eine echte Klasse daraus:
public class Entity { public Health Health; public Damage Damage; public Invincible Invincible;
Danach erstellt unser Generator den Code der Komponentenklassen "
Gesundheit" , "
Schaden" und "
Unbesiegbar" , der bereits in der Spielelogik verwendet wird:
public sealed class Health : IComponent { public int Hp; public void Reset() { Hp = default(int); }
Wie Sie sehen können, blieben die Daten in den Klassen und Methoden wurden hinzugefĂŒgt, z. B.
ZurĂŒcksetzen . Es ist erforderlich, um Komponenten in Pools zu optimieren und wiederzuverwenden. Andere Hilfsmethoden enthalten keine GeschĂ€ftslogik - ich werde sie der KĂŒrze halber nicht geben.
Es wird auch eine Klasse fĂŒr den Zustand der Welt generiert, die eine Liste aller Komponenten und EntitĂ€ten enthĂ€lt:
public sealed class GameState {
Und schlieĂlich der generierte Code fĂŒr
Entity :
public sealed class Entity { public uint Id;
Die
EntitÀtsklasse ist im Wesentlichen nur eine Komponentenkennung. Der Verweis auf die Objekte der
GameState- Welt wird nur in Hilfsmethoden verwendet, um das Schreiben von GeschĂ€ftslogikcode zu vereinfachen. Wenn wir die Kennung einer Komponente kennen, können wir damit Beziehungen zwischen EntitĂ€ten serialisieren und VerknĂŒpfungen in Komponenten zu anderen EntitĂ€ten implementieren. Beispielsweise enthĂ€lt die
Schadenskomponente einen Verweis auf die
Opfereinheit , um festzustellen, wer beschÀdigt wurde.
Dies beendet den generierten Code. Im Allgemeinen benötigen wir einen Generator, um nicht jedes Mal Hilfsmethoden zu schreiben. Wir beschreiben die Komponenten nur als Daten, dann erledigt der Generator die ganze Arbeit. Beispiele fĂŒr Hilfsmethoden:
- EntitÀten erstellen / löschen;
- HinzufĂŒgen / Entfernen / Kopieren einer Komponente, Zugriff darauf, falls vorhanden;
- vergleiche zwei Staaten der Welt;
- den Zustand der Welt serialisieren;
- Delta-Komprimierung;
- Code einer Webseite oder eines Unity-Fensters zur Anzeige des Zustands der Welt, der EntitÀten, der Komponenten (siehe Details unten);
- usw.
Fahren wir mit dem Systemcode fort. Sie definieren GeschÀftslogik. Schreiben wir zum Beispiel den Code eines Systems, das den Schaden eines Spielers berechnet:
public sealed class DamageSystem : ISystem { void ISystem.Execute(GameState gs) { foreach (var damage in gs.Damages) { var invincible = damage.Victim.Invincible; if (invincible != null) continue; var health = damage.Victim.Health; if (health == null) continue; health.Hp -= damage.Amount; } } }
Das System durchlÀuft alle
Schadenskomponenten der Welt und prĂŒft, ob ein potenziell beschĂ€digter Spieler (
Opfer ) eine
unbesiegbare Komponente enthÀlt. Wenn dies der Fall ist, ist der Spieler unverwundbar und es entsteht kein Schaden. Als nÀchstes erhalten wir die
Gesundheitskomponente des Opfers und reduzieren die Gesundheit des Spielers um die GröĂe des Schadens.
Betrachten Sie die Hauptmerkmale der Systeme:
- Ein System ist normalerweise eine zustandslose Klasse, enthĂ€lt keine internen Daten und versucht nicht, sie irgendwo zu speichern, auĂer fĂŒr Daten ĂŒber die Welt, die von auĂen ĂŒbertragen werden.
- Systeme durchlaufen normalerweise alle Komponenten eines bestimmten Typs und arbeiten mit ihnen. Sie werden normalerweise nach der Art der Komponente ( Damage â DamageSystem ) oder nach der von ihnen ausgefĂŒhrten Aktion ( RespawnSystem ) aufgerufen .
- Das System implementiert minimale FunktionalitĂ€t. Wenn wir beispielsweise weiter gehen, nachdem das DamageSystem ausgefĂŒhrt wurde, entfernt ein anderes RemoveDamageSystem alle Damage- Komponenten. Im nĂ€chsten Tick kann ein anderes ApplyDamageSystem, das auf dem SchieĂen des Spielers basiert, die Schadenskomponente erneut mit neuem Schaden aufhĂ€ngen. Und dann ĂŒberprĂŒft das PlayerDeathSystem den Zustand des Spielers ( Health.Hp ) und zerstört, wenn er kleiner oder gleich 0 ist, alle Komponenten des Spielers mit Ausnahme von Transform und fĂŒgt die Komponente Dead Flag hinzu.
Insgesamt erhalten wir die folgenden Klassen und die Beziehungen zwischen ihnen:

Einige Fakten zu ECS
ECS hat seine Vor- und Nachteile als Entwicklungsansatz und als ReprĂ€sentationsmethode fĂŒr die Welt des Spiels. Jeder entscheidet selbst, ob er es nutzt oder nicht. Beginnen wir mit den Profis:
- Zusammensetzung versus Mehrfachvererbung. Bei Mehrfachvererbung kann eine Reihe unnötiger Funktionen vererbt werden. Im Fall von ECS wird die FunktionalitĂ€t angezeigt / ausgeblendet, wenn eine Komponente hinzugefĂŒgt / entfernt wird.
- Trennung von Logik und Daten. Die FĂ€higkeit, die Logik zu Ă€ndern (Systeme Ă€ndern, Komponenten entfernen / hinzufĂŒgen), ohne Daten zu beschĂ€digen. Das heiĂt, Sie können die Gruppe von Systemen, die fĂŒr eine bestimmte FunktionalitĂ€t verantwortlich sind, jederzeit deaktivieren. Alles andere funktioniert weiterhin und dies hat keine Auswirkungen auf die Daten.
- Der Spielzyklus wird vereinfacht. Ein Update wird angezeigt und der gesamte Zyklus ist in Systeme unterteilt. Daten werden unabhÀngig von der Engine vom "Flow" im System verarbeitet (es gibt keine Millionen von Update- Aufrufen wie in Unity).
- Eine EntitÀt weià nicht, welche Klassen sie betreffen (und sollte es nicht wissen).
- Effiziente Speichernutzung . Dies hĂ€ngt von der Implementierung von ECS ab. Sie können erstellte EntitĂ€tsobjekte und -komponenten mithilfe von Pools wiederverwenden. Sie können Werttypen fĂŒr Daten verwenden und diese nebeneinander im Speicher speichern ( DatenlokalitĂ€t ).
- Es ist einfacher zu testen, wann Daten von der Logik getrennt sind. Besonders wenn man bedenkt, dass Logik ein kleines System mit mehreren Codezeilen ist.
- Zeigen Sie den Zustand der Welt in Echtzeit an und bearbeiten Sie ihn . Weil Der Zustand der Welt besteht nur aus Daten. Wir haben ein Tool geschrieben, das auf der Webseite den gesamten Zustand der Welt in einem Match auf dem Server (sowie die Matchszene in 3D) anzeigt. Jede Komponente einer EntitĂ€t kann angezeigt, geĂ€ndert oder gelöscht werden. Dasselbe kann im Unity-Editor fĂŒr den Client ausgefĂŒhrt werden.

Und jetzt die Nachteile:
- Sie mĂŒssen lernen, Code anders zu denken, zu entwerfen und zu schreiben . Denken Sie in EntitĂ€ten, Komponenten und Systemen. Viele Entwurfsmuster in ECS werden auf völlig andere Weise implementiert (siehe ein Beispiel fĂŒr die Implementierung des Zustandsmusters in einem der Ăbersichtsartikel am Ende).
- Mehr Code . Umstritten. Einerseits gibt es aufgrund der Tatsache, dass wir die Logik in kleine Systeme aufteilen, anstatt alle Funktionen in einer Klasse zu beschreiben, mehr Klassen, aber nicht viel mehr Code.
- Die Reihenfolge der aufrufenden Systeme beeinflusst den Betrieb des gesamten Spiels . Normalerweise sind die Systeme voneinander abhĂ€ngig, die Reihenfolge ihrer AusfĂŒhrung wird durch die Liste festgelegt und sie werden in dieser Reihenfolge ausgefĂŒhrt. Beispielsweise berĂŒcksichtigt DamageSystem zuerst den Schaden, dann entfernt RemoveDamageSystem die Damage- Komponente. Wenn Sie versehentlich die Reihenfolge Ă€ndern, funktioniert alles anders. Im Allgemeinen gilt dies auch fĂŒr den ĂŒblichen OOP-Fall, wenn Sie die Reihenfolge der Methodenaufrufe Ă€ndern. In ECS ist es jedoch einfacher, einen Fehler zu machen. Wenn beispielsweise ein Teil der Logik zur Vorhersage auf dem Client ausgefĂŒhrt wird, sollte die Reihenfolge dieselbe sein wie auf dem Server.
- Wir mĂŒssen die Daten und Ereignisse der Logik irgendwie mit der Ansicht verbinden . Im Fall von Unity haben wir MVP:
- Modell - GameState von ECS;
- Anzeigen - bei uns sind dies ausschlieĂlich Standardklassen fĂŒr MonoBehavior Unity ( Renderer , Text usw.) und FertighĂ€user.
- Presenter verwendet den GameState , um die Ereignisse des Auftretens / Verschwindens von EntitĂ€ten, Komponenten usw. zu bestimmen, erstellt Unity-Objekte aus FertighĂ€usern und Ă€ndert sie entsprechend den Ănderungen im Zustand der Welt.
Wussten Sie, dass:- Bei ECS geht es nicht nur um DatenlokalitĂ€t . FĂŒr mich ist dies eher ein Programmierparadigma, ein Muster, eine andere Art, die Spielwelt zu gestalten - nennen Sie es wie Sie wollen. Die DatenlokalitĂ€t ist nur eine Optimierung.
- Einheit hat kein ECS! Oft fragen Sie Kandidaten bei einem Teaminterview - was wissen Sie ĂŒber ECS? Wenn du nichts gehört hast, sagst du es ihnen und sie antworteten: "Ah, so ist es wie in Unity, dann weiĂ ich es!" Aber nein, es ist nicht wie in der Unity-Engine. Dort werden Daten und Logik in der MonoBehaviour- Komponente kombiniert, und GameObject (im Vergleich zu einer EntitĂ€t in ECS) verfĂŒgt ĂŒber zusĂ€tzliche Daten - einen Namen, einen Platz in der Hierarchie usw. Unity-Entwickler arbeiten derzeit an einer normalen Implementierung von ECS in der Engine, und bisher scheint es gut zu sein. Sie haben Spezialisten auf diesem Gebiet eingestellt - ich hoffe, es wird cool.
Unsere Auswahlkriterien fĂŒr das ECS-Framework
Als wir beschlossen, ein Spiel auf ECS zu entwickeln, suchten wir nach einer vorgefertigten Lösung und schrieben die Anforderungen dafĂŒr auf der Grundlage der Erfahrung eines der Entwickler auf. Und sie haben gemalt, wie vorhandene Lösungen unseren Anforderungen entsprechen. Es war vor einem Jahr, im Moment hĂ€tte sich etwas Ă€ndern können. Als Lösungen haben wir betrachtet:
- Entitas
- Artemis C #
- Ash.net
- ECS ist zu dem Zeitpunkt, als wir es konzipiert haben, unsere eigene Lösung. Das heiĂt, unsere Annahmen und WĂŒnsche, was wir selbst tun können.
Wir haben zum Vergleich eine Tabelle zusammengestellt, in der ich auch unsere aktuelle Lösung (als
ECS (jetzt) ââbezeichnet ) aufgenommen habe:
Rote Farbe - die Lösung unterstĂŒtzt unsere Anforderungen nicht, orange - teilweise unterstĂŒtzt, grĂŒn - vollstĂ€ndig unterstĂŒtzt.FĂŒr uns war die Analogie der Operationen fĂŒr den Zugriff auf Komponenten und die Suche nach EntitĂ€ten in ECS Operationen in einer SQL-Datenbank. Daher haben wir Konzepte wie Tabelle (Tabelle), Join (Join-Operation), Indizes (Indizes) usw. verwendet.
Wir werden unsere Anforderungen beschreiben und inwieweit Bibliotheken und Frameworks von Drittanbietern diesen entsprachen:
- Separate DatensĂ€tze (Verlauf, aktuell, visuell, statisch) - Die Möglichkeit, WeltzustĂ€nde separat abzurufen und zu speichern (z. B. den aktuellen Status fĂŒr die Verarbeitung, das Rendern, den Statusverlauf usw.). Alle berĂŒcksichtigten Entscheidungen unterstĂŒtzten diese Anforderung .
- EntitĂ€ts-ID als Ganzzahl - UnterstĂŒtzung fĂŒr die Darstellung einer EntitĂ€t durch ihre Identifikationsnummer. Es ist notwendig fĂŒr die Ăbertragung ĂŒber das Netzwerk und die FĂ€higkeit, EntitĂ€ten in der Geschichte der Staaten zu verbinden. Keine der als unterstĂŒtzt betrachteten Lösungen. In Entitas wird eine EntitĂ€t beispielsweise durch ein vollwertiges Objekt dargestellt (wie ein GameObject in Unity).
- Join durch ID O (N + M) - UnterstĂŒtzung fĂŒr eine relativ schnelle Abtastung von zwei Arten von Komponenten. Zum Beispiel, wenn Sie alle EntitĂ€ten mit Komponenten des Schadenstyps (z. B. deren N-Teile) und Gesundheit (M-Teile) zum Berechnen und Verursachen von Schaden erhalten mĂŒssen. Es gab volle UnterstĂŒtzung in Artemis; In Entitas und Ash.NET ist es schneller als O (NÂČ), aber langsamer als O (N + M). Ich kann mich jetzt nicht an die EinschĂ€tzung erinnern.
- Join durch ID-Referenz O (N + M) - das gleiche wie oben, nur wenn eine Komponente einer EntitĂ€t eine VerknĂŒpfung zu einer anderen hat und diese eine andere Komponente erhalten muss (in unserem Beispiel bezieht sich die Schadenskomponente der HilfsentitĂ€t auf die SpielerentitĂ€t Opfer und von dort mĂŒssen Sie die Gesundheitskomponente erhalten ). Wird von keiner der betrachteten Lösungen unterstĂŒtzt.
- Keine Abfragezuweisung - Keine zusĂ€tzlichen Speicherzuweisungen beim Abfragen von Komponenten und EntitĂ€ten aus dem Zustand der Welt. In Entitas war es in bestimmten FĂ€llen, aber fĂŒr uns unbedeutend.
- Pooltabellen - Speicherung von Weltdaten in Pools, Möglichkeit zur Wiederverwendung von Speicher, Zuordnung nur, wenn der Pool leer ist. Es gab "einige" UnterstĂŒtzung in Entitas und Artemis, eine völlige Abwesenheit in Ash.NET.
- Vergleich nach ID (add, del) - Integrierte UnterstĂŒtzung fĂŒr Ereignisse beim Erstellen / Zerstören von EntitĂ€ten und Komponenten nach ID. Die Anzeigeebene (Ansicht) muss Objekte ein- / ausblenden, Animationen und Effekte abspielen. Wird von keiner der betrachteten Lösungen unterstĂŒtzt.
- Î-Serialisierung (Quantisierung, Ăberspringen) - integrierte Delta-Komprimierung zur Serialisierung des Weltzustands (z. B. um die GröĂe der ĂŒber das Netzwerk gesendeten Daten zu verringern). Out of the Box wurde in keiner der Lösungen unterstĂŒtzt.
- Interpolation ist ein eingebauter Interpolationsmechanismus zwischen Weltstaaten. Keine der unterstĂŒtzten Lösungen.
- Komponententyp wiederverwenden - Die Möglichkeit, einmal geschriebenen Komponententyp in verschiedenen EntitĂ€tstypen zu verwenden. Nur unterstĂŒtzte Entitas .
- explizite Reihenfolge der Systeme - die Möglichkeit, eigene Anrufreihenfolgesysteme festzulegen. Alle Entscheidungen unterstĂŒtzt.
- Editor (Einheit / Server) - UnterstĂŒtzung fĂŒr das Anzeigen und Bearbeiten von EntitĂ€ten in Echtzeit, sowohl fĂŒr den Client als auch fĂŒr den Server. Entitas unterstĂŒtzte nur die Möglichkeit, EntitĂ€ten und Komponenten im Unity-Editor anzuzeigen und zu bearbeiten.
- schnelles Kopieren / Ersetzen - die Möglichkeit, Daten kostengĂŒnstig zu kopieren / ersetzen. Keine der unterstĂŒtzten Lösungen.
- Komponente als Werttyp (Struktur) - Komponenten als Werttypen. GrundsĂ€tzlich wollte ich darauf basierend eine gute Leistung erzielen. Es wurde kein einziges System unterstĂŒtzt, Komponentenklassen waren ĂŒberall.
Optionale Anforderungen (
keine der Lösungen unterstĂŒtzte sie zu diesem Zeitpunkt ):
- Indizes - Indizierung von Daten wie in einer Datenbank.
- zusammengesetzte SchlĂŒssel - komplexe SchlĂŒssel fĂŒr den schnellen Zugriff auf Daten (wie in der Datenbank).
- IntegritĂ€tsprĂŒfung - die FĂ€higkeit, die IntegritĂ€t von Daten in einem Zustand der Welt zu ĂŒberprĂŒfen. NĂŒtzlich zum Debuggen.
- Die inhaltsbewusste Komprimierung ist die beste Datenkomprimierung, die auf dem Wissen ĂŒber die Art der Daten basiert. Zum Beispiel, wenn wir die maximale GröĂe der Karte oder die maximale Anzahl von Objekten auf der Welt kennen.
- Typen- / Systembegrenzung - BeschrÀnkung der Anzahl der Arten von Komponenten oder Systemen. In Artemis war es zu dieser Zeit unmöglich, mehr als 32 oder 64 Arten von Komponenten und Systemen zu erstellen .
Wie aus der Tabelle hervorgeht, wollten wir alle Anforderungen auĂer den optionalen selbst implementieren. In der Tat haben wir im Moment
nicht getan:
- Join durch ID O (N + M) und Join durch ID-Referenz O (N + M) - Die Auswahl fĂŒr zwei verschiedene Komponenten belegt immer noch O (NÂČ) (tatsĂ€chlich eine verschachtelte for- Schleife). Andererseits gibt es nicht so viele EntitĂ€ten und Komponenten fĂŒr eine Ăbereinstimmung.
- Vergleich nach ID (add, del) - wird auf Framework-Ebene nicht benötigt. Wir haben dies auf einer höheren Ebene in MVP implementiert.
- schnelles Kopieren / Ersetzen und Komponente als Werttyp (Struktur) - irgendwann wurde uns klar, dass das Arbeiten mit Strukturen nicht so bequem ist wie mit Klassen und wir entschieden uns fĂŒr Klassen - wir bevorzugten Entwicklungskomfort anstelle einer besseren Leistung. Ăbrigens haben die Entitas-Entwickler am Ende dasselbe getan .
Gleichzeitig haben wir dennoch eine der Anforderungen realisiert, die unserer Meinung nach zunÀchst optional waren:
- inhaltsbewusste Komprimierung - aufgrund dessen konnten wir die GröĂe des ĂŒber das Netzwerk ĂŒbertragenen Pakets erheblich (zehnmal) reduzieren. FĂŒr mobile Datennetze ist es sehr wichtig, die PaketgröĂe in die MTU einzupassen, damit sie nicht in kleine Teile zerlegt wird, die verloren gehen können, in einer anderen Reihenfolge ablaufen und dann in Teile zusammengesetzt werden mĂŒssen. Wenn in Photon beispielsweise die DatengröĂe nicht in die MTU-Bibliothek passt, werden die Daten in Pakete aufgeteilt und als zuverlĂ€ssig (mit garantierter Zustellung) gesendet, selbst wenn Sie sie von oben als "unzuverlĂ€ssig" senden. Mit Schmerzen aus erster Hand getestet.
Merkmale unserer Entwicklung bei ECS
- Wir bei ECS schreiben ausschlieĂlich GeschĂ€ftslogik . Keine Arbeit mit Ressourcen, Ansichten usw. Da der ECS-Logikcode gleichzeitig auf dem Client in Unity und auf dem Server ausgefĂŒhrt wird, sollte er so unabhĂ€ngig wie möglich von anderen Ebenen und Modulen sein.
- Wir versuchen Komponenten und Systeme zu minimieren . Normalerweise starten wir fĂŒr jede neue Aufgabe neue Komponenten und Systeme. Manchmal kommt es jedoch vor, dass wir die alten Ă€ndern, den Komponenten neue Daten hinzufĂŒgen und die Systeme âaufblasenâ.
- In unserer ECS-Implementierung können Sie einer EntitĂ€t nicht mehrere Komponenten desselben Typs hinzufĂŒgen . Wenn ein Spieler in einem Tick mehrmals getroffen wurde (z. B. mehrere Gegner), erstellen wir normalerweise fĂŒr jeden Schaden eine neue EntitĂ€t und fĂŒgen ihr eine Schadenskomponente hinzu .
- Manchmal reicht die PrĂ€sentation nicht aus, um Informationen im GameState zu erhalten . Dann mĂŒssen Sie spezielle Komponenten oder zusĂ€tzliche Daten hinzufĂŒgen, die nicht an der Logik beteiligt sind, die die Ansicht jedoch benötigt. Zum Beispiel ist die Aufnahme sofort auf dem Server, ein Tick lebt und visuell ist sie auf dem Client lĂ€nger. Daher wird fĂŒr den Client der Schuss zum Parameter "Schusslebensdauer" hinzugefĂŒgt.
- Wir implementieren Ereignisse / Anforderungen, indem wir spezielle Komponenten erstellen . Wenn beispielsweise ein Spieler gestorben ist, hĂ€ngen wir ihm eine Komponente ohne tote Daten auf. Dies ist ein Ereignis fĂŒr andere Systeme und die Ansichtsebene, in der der Spieler gestorben ist. Oder wenn wir den Spieler auf den Punkt bringen mĂŒssen, erstellen wir mit der Respawn- Komponente eine separate EntitĂ€t mit zusĂ€tzlichen Informationen darĂŒber, wen wir wiederbeleben sollen. Ein separates RespawnSystem zu Beginn des Spielzyklus durchlĂ€uft diese Komponenten und schafft bereits die Essenz des Spielers. Das heiĂt, TatsĂ€chlich ist die erste EntitĂ€t eine Anforderung zum Erstellen der zweiten.
- Wir haben spezielle "Singleton" -Komponenten / -EntitÀten . Zum Beispiel haben wir eine EntitÀt mit ID = 1, an der spezielle Komponenten hÀngen - die Spieleinstellungen.
Bonus
â ECS â . , , , :
- Unity, ECS -- â ECS . mopsicus , ECS, . : Unity ECS , . . «» ECS Unity. ECS-, : LeoECS , BrokenBricksECS , Svelto.ECS .
- Unity3D ECS Job System â , ECS Unity. fstleo , Unity ECS, , - , JobSystem.
- Entity System Framework ? â Ash- ActionScript. , , OOP- ECS-.
- Ash Entity System â , FSM State ECS â , .
- Entity-Component-System â â ECS C++.