Ich lese Game Coding Complete und der Autor empfiehlt eine ereignisgesteuerte Kommunikation zwischen Spielobjekten und Modulen.
Grundsätzlich sollten alle lebenden Spielschauspieler über ein internes Ereignismeldesystem mit den Schlüsselmodulen (Physik, KI, Spielelogik, Spieleansicht usw.) kommunizieren. Dies bedeutet, dass Sie einen effizienten Event-Manager entwerfen müssen. Ein schlecht entworfenes System frisst CPU-Zyklen, insbesondere bei mobilen Plattformen.
Ist dies ein bewährter und empfohlener Ansatz? Wie soll ich entscheiden, ob ich es verwenden soll?
architecture
software-engineering
events
Bunkai.Satori
quelle
quelle
libuv
hat sich vor kurzem zu einer erfolgreichen Veranstaltungsbibliothek entwickelt. (Es ist in C. Node.js ist der bekannteste Anwendungsfall.)Antworten:
Dies ist eine Erweiterung meines Kommentars zu einer vollständigen Antwort, wie vorgeschlagen.
Ja , schlicht und einfach. Kommunikation muss stattfinden und es gibt Situationen, in denen "Sind wir schon da?" Polling-Typ ist erforderlich. Wenn die Dinge überprüft werden, ob sie etwas anderes tun sollen, wird im Allgemeinen Zeit verschwendet. Sie könnten sie stattdessen auf Dinge reagieren lassen, die ihnen gesagt werden. Ein klar definierter Kommunikationspfad zwischen Objekten / Systemen / Modulen beschleunigt die parallele Einrichtung erheblich.
Ich habe über Stack Overflow einen allgemeinen Überblick über ein Ereignismeldesystem gegeben . Ich habe es von der Schule an in professionellen Spieletiteln und jetzt in Nicht-Spielprodukten verwendet, die natürlich jedes Mal an den Anwendungsfall angepasst wurden.
BEARBEITEN : Um eine Kommentarfrage zu beantworten, woher Sie wissen, welche Objekte die Nachricht erhalten sollen : Die Objekte selbst sollten
Request
über Ereignisse benachrichtigt werden. IhrEventMessagingSystem
(EMS) benötigt einRegister(int iEventId, IEventMessagingSystem * pOjbect, (EMSCallback)fpMethodToUseForACallback)
sowie ein MatchingUnregister
(einen eindeutigen Eintrag für einiEventId
aus dem Objektzeiger und Rückruf). Auf diese Weise kann ein Objekt, wenn es etwas über eine Nachricht wissen möchte,Register()
mit dem System verbunden werden. Wenn es nicht mehr über die Ereignisse Bescheid wissen muss, kann esUnregister()
. Natürlich möchten Sie einen Pool dieser Callback-Registrierungsobjekte und eine effektive Möglichkeit, sie zu Listen hinzuzufügen oder daraus zu entfernen. (Normalerweise habe ich selbstordnende Arrays verwendet. Eine ungewöhnliche Art zu sagen, dass sie ihre eigenen Zuordnungen zwischen einem Poolstapel nicht verwendeter Objekte und Arrays verfolgen, deren Größe bei Bedarf geändert wird.)BEARBEITEN : Für ein voll funktionsfähiges Spiel mit einer Update-Schleife und einem Event-Messaging-System möchten Sie vielleicht ein altes Schulprojekt von mir ausprobieren . Der oben verlinkte Stapelüberlauf-Beitrag verweist ebenfalls darauf.
quelle
Meiner Meinung nach solltest du einfach anfangen, dein Spiel zu entwickeln und umzusetzen, womit du dich wohl fühlst. Wenn Sie dies tun, werden Sie feststellen, dass Sie an einigen Stellen MVC verwenden, an anderen jedoch nicht. Ereignisse an einigen Orten, aber nicht an anderen; Bestandteile einiger Orte, aber Vererbung anderer; sauberes Design an einigen Orten und crufty Design an anderen.
Und das ist in Ordnung, denn wenn Sie fertig sind, haben Sie tatsächlich ein Spiel und ein Spiel ist viel cooler als ein Nachrichtenübermittlungssystem.
quelle
Eine bessere Frage ist, welche Alternativen gibt es? Wie können Sie diese Systeme in einem solch komplexen System mit richtig unterteilten Modulen für Physik, KI usw. orchestrieren?
Message Passing scheint die "beste" Lösung für dieses Problem zu sein. Ich kann mir momentan keine Alternativen vorstellen. In der Praxis gibt es jedoch zahlreiche Beispiele für die Weitergabe von Nachrichten. Tatsächlich verwenden Betriebssysteme die Nachrichtenübermittlung für einige ihrer Funktionen. Aus Wikipedia :
(Interprozesskommunikation ist die Kommunikation zwischen Prozessen (dh die Ausführung von Programminstanzen) innerhalb der Betriebssystemumgebung.)
Wenn es also gut genug für ein Betriebssystem ist, ist es wahrscheinlich gut genug für ein Spiel, oder? Es gibt auch andere Vorteile, aber ich lasse den Wikipedia-Artikel über das Versenden von Nachrichten das Erklären übernehmen.
Ich habe auch eine Frage zu Stack Overflow gestellt: "Datenstrukturen für die Nachrichtenübergabe in einem Programm?" , die Sie vielleicht überlesen möchten.
quelle
Nachrichten funktionieren im Allgemeinen gut, wenn:
Je mehr Ihre Anforderungen mit dieser Liste übereinstimmen, desto besser sind die Nachrichten. Im Allgemeinen sind sie ziemlich gut. Sie verschwenden keine CPU-Zyklen, nur um nichts anderes zu tun als Abfragen oder andere globalere Lösungen. Sie können fantastisch Teile einer Codebasis entkoppeln, was immer hilfreich ist.
quelle
Gute Antworten bisher von James und Ricket, ich antworte nur, um einen Hinweis zur Vorsicht hinzuzufügen. Nachrichtenübermittlung / ereignisgesteuerte Kommunikation ist sicherlich ein wichtiges Werkzeug im Arsenal des Entwicklers, kann aber leicht überbeansprucht werden. Wenn Sie einen Hammer haben, sieht alles aus wie ein Nagel und so weiter.
100% ig sollten Sie über den Datenfluss rund um Ihren Titel nachdenken und sich darüber im Klaren sein, wie Informationen von einem Subsystem zu einem anderen übertragen werden. In einigen Fällen ist das Weiterleiten von Nachrichten eindeutig am besten. in anderen Fällen kann es zweckmäßiger sein, wenn ein Subsystem über eine Liste gemeinsam genutzter Objekte arbeitet, sodass auch andere Subsysteme auf derselben gemeinsam genutzten Liste arbeiten können. und viele weitere Methoden.
Sie sollten jederzeit wissen, welche Subsysteme auf welche Daten zugreifen müssen und wann sie darauf zugreifen müssen. Dies wirkt sich auf Ihre Fähigkeit zur Parallelisierung und Optimierung aus und hilft Ihnen, die schleichenderen Probleme zu vermeiden, wenn verschiedene Teile Ihres Motors zu eng miteinander verwoben sind. Sie müssen darüber nachdenken, unnötiges Kopieren von Daten zu minimieren und wie sich Ihr Datenlayout auf die Cache-Nutzung auswirkt. All dies führt Sie zur jeweils besten Lösung.
Abgesehen davon hatte so ziemlich jedes Spiel, an dem ich jemals gearbeitet habe, ein solides asynchrones Benachrichtigungssystem für Nachrichtenübermittlung und Ereignisse. Es ermöglicht Ihnen, prägnanten, effizienten und wartbaren Code zu schreiben, selbst angesichts komplexer und sich schnell ändernder Designanforderungen.
quelle
Nun, ich weiß, dass dieser Beitrag ziemlich alt ist, aber ich konnte nicht widerstehen.
Ich habe vor kurzem eine Game-Engine gebaut. Es verwendet 3D-Party-Bibliotheken für Rendering und Physik, aber ich habe den Kernteil geschrieben, der die Entitäten und die Spiellogik definiert und verarbeitet.
Der Motor folgt sicherlich einem traditionellen Ansatz. Es gibt eine Hauptaktualisierungsschleife, die die Aktualisierungsfunktion für alle Entitäten aufruft. Kollisionen werden direkt per Rückruf an die Entitäten gemeldet. Die Kommunikation zwischen Entitäten erfolgt über intelligente Zeiger, die zwischen Entitäten ausgetauscht werden.
Es gibt ein primitives Nachrichtensystem, das nur eine kleine Gruppe von Entitäten zu Engine-Nachrichten verarbeitet. Es ist vorzuziehen, diese Nachrichten am Ende einer Spielinteraktion zu verarbeiten (Beispiel: Erstellung oder Zerstörung einer Entität), da sie mit der Aktualisierungsliste in Konflikt geraten können. Am Ende jeder Spielrunde wird eine kleine Liste von Nachrichten verbraucht.
Trotz des primitiven Nachrichtensystems würde ich sagen, dass das System größtenteils auf "Aktualisierungsschleifen" basiert.
Gut. Nachdem ich dieses System benutzt habe, denke ich, dass es sehr einfach, schnell und gut organisiert ist. Die Spiellogik ist sichtbar und in sich geschlossen, nicht dynamisch wie eine Nachricht. Ich würde es wirklich nicht ereignisgesteuert machen, da meiner Meinung nach Ereignissysteme die Spielelogik unnötig komplizieren und den Spielcode sehr schwer zu verstehen und zu debuggen machen.
Aber ich denke auch, dass ein reines "Update Loop-basiertes" System wie das meine auch einige Probleme hat.
In einigen Momenten befindet sich beispielsweise eine Entität möglicherweise in einem "Nichtstun" -Zustand, wartet darauf, dass sich der Spieler nähert, oder etwas anderes. In den meisten Fällen verbrennt die Entität die Prozessorzeit für nichts und es ist besser, die Entität auszuschalten und sie einzuschalten, wenn ein bestimmtes Ereignis eintritt.
Also werde ich in meiner nächsten Spiel-Engine einen anderen Ansatz verfolgen. Die Entitäten registrieren sich für Motoroperationen wie Aktualisieren, Zeichnen, Kollisionserkennung und so weiter. Jedes dieser Ereignisse verfügt über separate Listen von Entitätsschnittstellen für die tatsächlichen Entitäten.
quelle
Ja. Es ist eine sehr effiziente Möglichkeit für Spielsysteme, miteinander zu kommunizieren. Ereignisse helfen Ihnen, viele Systeme zu entkoppeln und es sogar zu ermöglichen, Dinge separat zu kompilieren, ohne dass Sie die Existenz der anderen kennen. Dies bedeutet, dass Ihre Klassen einfacher prototypisiert werden können und die Kompilierungszeiten schneller sind. Noch wichtiger ist, dass Sie am Ende ein Flat-Code-Design anstelle eines Abhängigkeits-Chaos haben.
Ein weiterer großer Vorteil von Ereignissen besteht darin, dass sie problemlos über ein Netzwerk oder einen anderen Textkanal gestreamt werden können. Sie können sie für die spätere Wiedergabe aufnehmen. Die Möglichkeiten sind endlos.
Ein weiterer Vorteil: Es können mehrere Subsysteme auf dasselbe Ereignis warten. Zum Beispiel können alle Ihre Remote-Ansichten (Spieler) automatisch das Ereignis zum Erstellen von Entitäten abonnieren und Entitäten auf jedem Client erstellen, ohne dass Sie dies tun müssen. Stellen Sie sich vor, wie viel mehr Arbeit wäre, wenn Sie keine Ereignisse verwenden würden: Sie müssten
Update()
irgendwo Anrufe tätigen oder möglicherweiseview->CreateEntity
von der Spielelogik aus aufrufen (wo Kenntnisse über die Ansicht und die benötigten Informationen nicht dazugehören). Es ist schwer, dieses Problem ohne Ereignisse zu lösen.Mit Ereignissen erhalten Sie eine elegante und entkoppelte Lösung, die eine unbegrenzte Anzahl von Objekten unbegrenzter Art unterstützt, die alle einfach Ereignisse abonnieren und ihre Sache tun können, wenn etwas in Ihrem Spiel passiert. Deshalb sind Events großartig.
Weitere Details und eine Implementierung hier .
quelle
Nach dem, was ich gesehen habe, scheint es nicht sehr verbreitet zu sein, eine Engine zu haben, die vollständig auf Messaging basiert. Natürlich gibt es Subsysteme, die sich sehr gut für ein solches Nachrichtensystem eignen, wie zum Beispiel Netzwerke, GUI und möglicherweise andere. Im Allgemeinen kann ich mir jedoch einige Probleme vorstellen:
Mit dem gängigen Spielentwickler-Ansatz "Es muss möglichst effizient sein" sind solche Nachrichtensysteme also nicht so verbreitet.
Ich bin jedoch damit einverstanden, dass Sie einfach weitermachen und es versuchen sollten. Mit einem solchen System sind sicherlich viele Vorteile verbunden, und Rechenleistung ist heutzutage kostengünstig verfügbar.
quelle