Du bist nicht angemeldet.

Werbeanzeige

buggypixels

Treue Seele

Beiträge: 125

Wohnort: Meerbusch

Beruf: Programmierer

  • Private Nachricht senden

21

06.01.2015, 13:28

Das über Events zu steuern hört sich furchtbar an. Eine MoveComponent würde sagen "Kann mal jemand Entity 4711 um 2 Einheiten nach links bewegen? Also falls jemand dafür zuständig ist"
Eher hätte ich eine PositionComponent und eine VelocityComponent und dann ein MoveSystem. Das würde dann jede Entity bearbeiten, die beide Components hat. Das ist zumindest
ein Ansatz den manche verwenden. Daraus ergibt sich dann auch autoamtisch die Zuordnung zu einem System. Also die Menge an Components definieren zu welchen Systems ein Entity
gehört. Sprich, wenn es eine Position und eine Geschwindigkeit hat, dann soll es vom MoveSystem bewegt werden. Das MoveSystem bewegt halt alles, was die beiden Komponenten hat.
Das Gleiche würde dann gelten, wenn eine Entity eine PositionComponent, eine MaterialComponent und eine MeshComponent hat, dann soll es vom RenderSystem auch gezeichnet werden.
Aber wie gesagt, dass ist nur ein möglicher Ansatz.

Schorsch

Supermoderator

Beiträge: 5 206

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

22

06.01.2015, 13:36

Ich verstehe das Problem von Eventsystemen nicht. Zugegeben mein Beispiel war nicht besonders schön gewählt und ob ich es selbst so umsetzen würde darüber habe ich mir noch gar keine Gedanken gemacht, aber solche Eventsysteme haben meiner Meinung nach auch Vorteile. Wenn jede Komponente für sich steht und nach außen nur über Events kommuniziert so kann ich einzelne Komponenten beliebig austauschen ohne groß etwas am Code ändern zu müssen. Wenn ich die Events weg lassen möchte und mit konventionellen Methodenaufrufen arbeiten möchte so müssen die einzelnen Systeme zumindest die Typen der einzelnen Komponenten kennen um damit zu arbeiten.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

BlueCobold

Community-Fossil

Beiträge: 10 859

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

23

06.01.2015, 13:39

Die Systeme müssen immer die Komponenten kennen auf denen sie operieren, egal ob via Events oder direkten Methodenaufruf.
Der Event-Ansatz hört sich erstmal ganz nett an, ist in der Praxis in diesem Ausmaß aber eine Katastrophe. Android kommuniziert quasi überall so und das ist schlimm, richtig, richtig schlimm.
Austauschen kannst Du die Komponenten ja trotzdem, ich sehe da keinen Grund, warum das nicht gehen sollte. Das Problem, was sich aber langsam kristallisiert, ist, dass man jede Entity an jedes System schicken muss, weil man vorher gar nicht weiß, für welche Components ein System überhaupt zuständig ist und ob das nur eine oder gar mehrere sind. Das finde ich sehr unschön und sollte man irgendwie umgehen können - eine einmalige Registrierung macht Sinn, allerdings sind die Components einer Entity dann recht statisch, da dürfen nicht einfach nach der Registrierung mal welche entfernt werden. Registrierung selbst ist aber auch nicht sonderlich toll, da schwirren die Instanzen letztlich doch überall im System umher.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »BlueCobold« (06.01.2015, 13:46)


Schorsch

Supermoderator

Beiträge: 5 206

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

24

06.01.2015, 14:06

Bei einem Eventansatz muss das System die Komponenten nicht unbedingt kennen. Es muss die möglichen Events kennen. Das System könnte zum Beispiel bei der Erzeugung einer Komponente als Parameter übergeben werden. Die Komponente kann sich nun selbst für die benötigten Events registrieren. Zusätzlich kann die Komponente das System für eigene Events registrieren. Weiterhin kann dafür gesorgt werden dass die Komponenten sich auch wieder eigenständig abmelden. So könnten Komponenten auch zur Laufzeit hinzugefügt bzw entfernt werden. Das System selbst muss also gar nicht wissen wie es mit Komponenten kommuniziert, sondern weiß nur dass es Events erhalten kann und darauf reagiert (diese weiter leitet). Statt der Events kann ich natürlich genau so gut Methoden direkt aufrufen, habe dann aber den Nachteil dass das System die Typen der einzelnen Komponenten kennen muss. Ist halt ein anderer Ansatz.
Ein Entity sendet in diesem Fall auch nicht an jedes System, sondern feuert ein Event und das bekommen eben nur die Systeme mit die sich dafür registriert haben. In diesem Fall haben die Systeme sich ja sogar nur indirekt registriert. Die Arbeit übernimmt die Komponente mehr oder weniger.

Quellcode

1
2
3
4
5
6
7
8
9
public SampleComponent(SampleSystem sampleSystem)
{
    sampleSystem.EventXYZ += DoSomething();
    this.EventABC += sampleSystem.DoSomething();
}

// ................

components.Add(new SampleComponent(this));


Wie gesagt ich finde das jetzt nicht unbedingt schlechter.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

BlueCobold

Community-Fossil

Beiträge: 10 859

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

25

06.01.2015, 14:23

Bei einem Eventansatz muss das System die Komponenten nicht unbedingt kennen. Es muss die möglichen Events kennen.
Das ist aber ziemlicher Quatsch. Du konvertierst da eine Datendefinition einer Component in eine andere eines Events. Das kannst Du Dir auch gleich sparen, indem du statt der festen Component ein Interface verwendest. Das System kennt dann nur das Interface und nicht die konkrete Component-Instance.
Wo registriert sich denn Dein System für die Events genau? Da braucht es ja auch noch eine zentrale Registrierungsstelle, die alle Beteiligten Components und Systeme kennen müssen. Das macht die Sache ja gleich noch viel hässlicher.
Den Direktaufruf propagierst du aktuell daher als schlecht, dass die Component-Types bekannt sind. Wenn Du allerdings Interfaces verwendest, ist dieses Argument plötzlich void. Andersherum könnte man argumentieren, dass bei deinem Ansatz die Messagetypes bekannt sein müssen und darüber hinaus auch noch kompatibel und dass jede neue Component auch noch eine neue Message braucht. Der einzige Vorteil, den ich tatsächlich sehe, ist die Filterung nach bestimmten Events. Das entspricht etwa dem, was ich im vorherigen Post als "einmalige Registrierung der relevanten Entities" bezeichnet habe. Den kompletten Message-Overhead würde man sich sparen und auch die Event-Werferei der Messages.

Der noch wesentlich größere Vorteil meines Ansatzes wäre, dass Du jederzeit neue Systeme hinzufügen kannst, die andere bestehende Components nutzt, sagen wir z.B. es braucht 10 von allen 100 existierenden Components und berechnet daraus etwas neues. Und das, ohne dafür ein neues Event erschaffen zu müssen. Mein Ansatz würde sich diese Components direkt von der Entity ziehen, die ja einmal beim System registriert wurde. Dein Ansatz müsste erstmal 10 verschiedene Events fangen, sie richtig einander zuordnen (wie auch immer es das genau tun will) und zwischendrin speichern und aggregieren. Oder du brauchst wahlweise eine neue Message und musst jetzt *irgendwie* alle Entities davon überzeugen diese zu werfen. Nicht sonderlich hübsch.

Klar, Events kann man dafür verwenden. Ist aber nicht toll. Solche Sachen haben wir in ähnlicher Form in diversen Projekten, wo wir Daten aus 5 verschiedenen Soap-Methoden ziehen, um daraus eine aggregierte Information anzuzeigen. Die zu sammeln ist schon schlimm, aber wenn sie dann auch noch ungeordnet durch Events ankommen, dann wird's richtig hässlich.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »BlueCobold« (06.01.2015, 14:32)


Schorsch

Supermoderator

Beiträge: 5 206

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

26

06.01.2015, 14:34

Die Events würden ja in meinem Fall den Methoden die normal aufgerufen würden entsprechen. Wenn die Kopmonente die Verknüpfung zwischen sich selbst und dem System erledigt so muss eine Komponente alle mit ihm verbundenen Systeme kennen, das System aber nicht die Komponente. Das Interface für eine Komponente muss also keine Methoden für Logik selbst kennen da das System diese nicht benötigt. Damit das System und Komponente verbunden werden würde ich das System einfach im Konstruktor der Komponente übergeben und dort dann die Verknüpfung durchführen. Bei mehreren Systemen natürlich eine Liste von Systemen.
Der Vorteil den ich sehe lässt sich relativ schnell beschreiben. Stell dir vor du entwickelst deine Spiellogik und dein Spiel ist mehr oder weniger fertig. Sounds und Musik gibt es noch nicht. Jetzt entwickelst du eine Soundkomponente. Die einzelnen Systeme musst du nicht mehr anpacken. Du musst ihnen nur die neue Komponente zufügen und bist fertig damit. Die restliche neue Logik wird in der Soundkomponente selbst umgesetzt. Du musst also nicht in jedem System selbst an den passenden Stellen dafür sorgen dass der Sound abgespielt wird. Du kannst deine Komponenten hinzufügen und entfernen und so die Logik erweitern ohne dass du in die Systeme eingreifen musst. Zumindest solange du keine neuen Events hast. Beim Sound könnte man wieder darüber streiten diesen als System umzusetzen.
Ich sag damit ja nicht das Eventsysteme der heilige Gral sind.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

BlueCobold

Community-Fossil

Beiträge: 10 859

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

27

06.01.2015, 14:35

Moment, Moment. Du willst, dass die Komponenten die Systeme kennen? Das finde ich sehr schlecht. Das ist ja so als würde ein Buch die Druckerei, den Verlag, die Buchhandlung, den Leser und die Recycling-Anglage kennen. Finde ich nicht gut. Da musst Du ja jede Komponente anfassen, sobald es ein neues System gibt.
Ich würde das eben genau andersrum machen: Wird eine Entity erzeugt, wird sie an alle Systeme geschickt. Jedes System schaut nach, ob die Entity die Components besitzt, die das System nutzt und merkt sich die Referenz (oder eben nicht). Beim Processing geht jedes System dann alle registrierten Entities durch, holt sich die Components und macht damit, was immer notwendig ist. Die Components und Entities wissen nicht mal, dass es überhaupt Systeme gibt. Wozu auch?

Deiner zweiter Absatz ist überflüssig, denn genau darüber reden wir ja die ganze Zeit - ein ECS. Das geht mit Events und ohne auch.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

BlueCobold

Community-Fossil

Beiträge: 10 859

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

28

06.01.2015, 15:18

Das ECS lässt sich mit Data-Driver vereinen, ist jetzt aber nicht die Hauptmotivation für ein ESC.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Schorsch

Supermoderator

Beiträge: 5 206

Wohnort: Wickede

Beruf: Student

  • Private Nachricht senden

29

06.01.2015, 15:34

Und man soll ja nicht für jede Eigenschaft eine Komponente erzeugen. Ich glaube wir reden hier teilweise auch aneinander vorbei. Das Komponenten Systeme kennen ist sicherlich nicht besonders schön, das stimmt schon. Könnte man natürlich in eine Factory oder vergleichbares auslagern was das ganze aber nur bedingt besser machen würde.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

Julién

Alter Hase

  • »Julién« ist der Autor dieses Themas

Beiträge: 723

Wohnort: Bayreuth

Beruf: Student | Hilfswissenschaftler in der Robotik

  • Private Nachricht senden

30

06.01.2015, 16:08

Ich schildere meinen Ansatz, wie ich ihn mir teilweise erdacht habe.

Entitys haben eine ID, aber auch die Components.
Die Systeme benötigen jeweils ein bestimmtes Set aus Components.

Meine Idee daher war es, eine Bitmask / Bitset / List<bool> zu definieren. Die Systeme haben jeweils ein solche Bitset und die Entitys.
Das des Systems ist statisch, d.h. es wird nur einmal gesetzt und das nur durch den base constructor.

Das der Entitys verändert sich, je nachdem ob man Components hinzufügt oder entfernt.

Jedes Component hat genau eine TypID, die auch dann einem Index im Bitset bzw. in der List entspricht.

Dann jedes mal wenn ein Entity hinzugefügt wird, werden die Bitset mit den jeweiligen Bitsets der Systeme verglichen und gegebenfalls hinzugefügt.

Somit muss das Component nichts von einem System wissen, aber das System weis aber welche Systeme es braucht.

Wie die im Components im Inneren aussehen ist dann egal. Außerdem kann ich dann getComponent<T>() auf ein Entity aufrufen und meist sicher eine Referenz erwarten.
Ich schaue nur mal ob ich das Registrieren der Components an den ComponentManager (also das Ding, das jedem Component eine ID zuweist) per CRTP löse.

Ich hoffe ich konnte meinen Gedankengang verständlich darlegen.
I write my own game engines because if I'm going to live in buggy crappy filth, I want it to me my own - Ron Gilbert

Werbeanzeige