Funktionsaufrufe pro Frame im Vergleich zu ereignisgesteuertem Messaging im Spieldesign

11

Das traditionelle Spieldesign , wie ich es kenne, verwendet Polymorphismus und virtuelle Funktionen, um den Status von Spielobjekten zu aktualisieren. Mit anderen Worten, derselbe Satz virtueller Funktionen wird in regelmäßigen Intervallen (z. B. pro Frame) für jedes Objekt im Spiel aufgerufen.

Kürzlich entdeckte ich, dass es ein anderes ereignisgesteuertes Nachrichtensystem gibt , mit dem der Status von Spielobjekten aktualisiert werden kann. Hier werden die Objekte normalerweise nicht pro Frame aktualisiert. Stattdessen wird ein hocheffizientes Ereignisnachrichtensystem erstellt , und Spielobjekte werden erst aktualisiert, nachdem eine gültige Ereignisnachricht empfangen wurde.

Event Driven Game Architecture ist gut beschrieben in: Game Coding Complete von Mike McShaffry .

Könnte ich Sie bitte um Hilfe bei folgenden Fragen bitten:

  • Was sind die Vor- und Nachteile beider Ansätze?
  • Wo ist einer besser als der andere?
  • Ist Event Driven Game Design universell und in allen Bereichen besser? Wird es daher auch für mombile Plattformen empfohlen?
  • Welches ist effizienter und welches ist schwieriger zu entwickeln?

Zur Verdeutlichung geht es bei meiner Frage nicht darum, Polymorphismus vollständig aus einem Spieldesign zu entfernen. Ich möchte einfach den Unterschied verstehen und von der Verwendung von ereignisgesteuertem Messaging im Vergleich zu regulären (pro Frame) Aufrufen virtueller Funktionen profitieren, um den Spielstatus zu aktualisieren.


Beispiel: Diese Frage hat hier einige Kontroversen ausgelöst. Lassen Sie mich Ihnen ein Beispiel geben: Laut MVC ist die Spiel-Engine in drei Hauptteile unterteilt:

  1. Anwendungsschicht (Hardware- und Betriebssystemkommunikation)
  2. Spielelogik
  3. Spielansicht

In einem Rennspiel ist die Spieleansicht dafür verantwortlich, dass der Bildschirm so schnell wie möglich mit mindestens 30 Bildern pro Sekunde gerendert wird. Game View wartet auch auf Eingaben des Spielers. Nun passiert dies:

  • Der Spieler drückt das Kraftstoffpedal auf 80%
  • GameView erstellt eine Meldung "Car 2 Fuel Pedal auf 80% gedrückt" und sendet sie an Game Logic.
  • Game Logic erhält die Nachricht, wertet sie aus, berechnet die Position und das Verhalten des neuen Autos und erstellt die folgenden Nachrichten für GameView: "Auto 2-Kraftstoffpedal ziehen 80% gedrückt", "Auto 2-Geräuschbeschleunigung", "Auto 2-Koordinaten X, Y". .
  • GameView empfängt die Nachrichten und verarbeitet sie entsprechend
Bunkai.Satori
quelle
wo hast du gefunden? einige Links oder Verweise? Ich kenne diesen Ansatz nicht (aber ich kenne ein ziemlich gutes Designmuster im Allgemeinen und empfehle eine gute Verwendung der Prinzipien der Objektorientierung im Allgemeinen), aber ich denke, dass ereignisbasiertes besser ist. Denken Sie an die Evolution in Netzwerksystemen: von Abfrage zu asynchronen Aufrufen. Es ist in Berechnungen und in der Abstraktionsebene optimiert
nkint
Hallo Nkint, danke für deinen Kommentar. Grundsätzlich wollte ich ereignisgesteuerte Kommunikation mit Aufrufen virtueller Funktionen vergleichen. Ich werde meine Frage etwas ändern. Übrigens, werfen Sie einen Blick auf diesen Link, der Spielmuster enthält: gameprogrammingpatterns.com .
Bunkai.Satori
5
Vielleicht bin ich dumm, aber wie können Sie ein Messaging-System ohne Polymorphismus zum Laufen bringen ? Benötigen Sie keine Basisklasse (abstrakt oder anderweitig), um Ihre Ereignisempfängerschnittstelle zu definieren? (Bearbeiten: vorausgesetzt, Sie arbeiten nicht in einer Sprache mit angemessener Reflexion.)
Tetrad
2
Die Effizienz wird auch stark von den Implementierungsdetails abhängen. Ich denke nicht, dass "welches effizienter ist" eine Frage ist, die in ihrer aktuellen Form beantwortet werden kann.
Tetrad
1
Spielobjekte müssen ankreuzen. Spielobjekte müssen miteinander kommunizieren. Diese beiden Dinge müssen beide passieren. Das erste, was Sie nicht mit Messaging machen, weil es redundant ist (Sie haben wahrscheinlich eine Liste aller Objekte irgendwo, rufen Sie updatesie einfach auf). Das zweite können Sie aus verschiedenen Gründen mit Messaging tun.
Tetrad

Antworten:

8

Ich bin fest davon überzeugt, dass die Notwendigkeit die Mutter der Erfindung ist. Ich mag es nicht, etwas zu codieren, es sei denn, sein Bedarf ist klar und klar definiert. Ich denke, wenn Sie Ihr Projekt durch Einrichten eines Event-Messaging-Systems starten, machen Sie es falsch. Ich glaube, dass Sie sich erst dann darauf konzentrieren sollten, wie Sie diese Module miteinander verbinden, wenn Sie Ihre Infrastruktur erstellt und getestet haben und alle Teile Ihres Projekts als genau definierte Arbeitsmodule haben. Der Versuch, ein Event-Messaging-System zu entwerfen, bevor Sie die Form und die Anforderungen der einzelnen Module verstehen, ist nicht in Ordnung.

Was sind die Vor- und Nachteile beider Ansätze?

Ich denke, einige Leute würden argumentieren, dass es gute Messaging-Systeme gibt, die installiert und verwendet werden können. Vielleicht ist das wahr. Sicherlich wäre die Leistung einer maßgeschneiderten Lösung, die speziell auf Ihre Bedürfnisse zugeschnitten ist, höher als die eines allgemeinen Nachrichtenbusses. Die große Frage ist: Wie viel Zeit werden Sie für den Aufbau eines Messagingsystems aufwenden, anstatt etwas zu verwenden, das bereits erstellt wurde. Wenn Sie ein Ereignissystem mit genau den Funktionen finden, die Sie benötigen, ist dies natürlich eine ziemlich einfache Entscheidung. Deshalb stelle ich sicher, dass ich genau verstehe, was ich brauche, bevor ich diese Entscheidung treffe.

Wo ist einer besser als der andere?

Wir könnten hier über Speicher und Ressourcen sprechen. Wenn Sie für Hardware mit begrenzten Ressourcen entwickeln, ist es sicherlich ein Problem, ein Ereignissystem zu verwenden, das dies erheblich einschränkt. Wirklich, ich denke, das Problem hängt davon ab, was Sie brauchen. Wie ich bereits erwähnt habe, wissen Sie es erst, wenn Sie sehen, wie alle Teile aussehen. Wenn Sie genug Erfahrung mit dem Aufbau dieser Systeme haben und genau wissen, wie alle Teile im Voraus aussehen werden, können Sie diese Frage auch im Voraus beantworten. Ich vermute, Sie haben diese Erfahrung nicht, da Sie diese Frage sonst nicht stellen würden.

Ist Event Driven Game Design universell und in allen Bereichen besser? Wird es daher auch für den Einsatz auf mobilen Plattformen empfohlen?

Universell und besser in allen Bereichen? Eine so pauschale Aussage wird leicht abgelehnt. Alles, was zusätzlichen Aufwand verursacht, muss seinen Anteil an der Arbeitslast tragen. Wenn Sie nicht genug Ereignisse verwenden, um den Overhead des Designs zu gewährleisten, ist es das falsche Design.

Welches ist effizienter und welches ist schwieriger zu entwickeln?

Die Effizienz hängt davon ab, wie sie umgesetzt wird. Ich denke, dass ein gut entwickeltes traditionelles Design ein ereignisbasiertes System an jedem Tag der Woche übertreffen wird. Dies liegt daran, dass die Kommunikation zwischen Teilen mikro-verwaltet und sehr effizient gestaltet werden kann. Dies macht es natürlich auch schwieriger, unter dem Gesichtspunkt der Erfahrung und der Zeit zu entwerfen, die erforderlich sind, um es fertigzustellen und effizienter zu gestalten. Wenn Ihnen diese Erfahrung fehlt oder Sie nicht die Zeit haben, die Anwendung gut zu entwickeln, ist die Verwendung eines ereignisbasierten Designs, das Ihren Anforderungen entspricht, effizienter. Wenn Sie benutzerdefinierte Ereignisanforderungen haben, die nicht einfach in eine ereignisbasierte Struktur passen, kann dies das Entwerfen der ereignisbasierten Struktur sehr schwierig machen - insbesondere, um das Design effizient zu halten.

Erick Robertson
quelle
Hallo Eric, danke für deine ausführliche Meinung zu meiner Frage. Wenn ich die Antworten von Ihnen und anderen lese, bewirkt die Implementierung von Ereignismeldungen wahrscheinlich kein Wunder bei der Steigerung der Gesamtleistung des Spiels. Stattdessen wird es die Dinge sehr komplizieren. Ich würde gerne weitere Antworten sehen, bevor ich diese Frage schließe. Da das ganze Buch dieses Thema behandelte, schien es eine gute Idee zu sein, darüber nachzudenken. Ich bin mir nicht sicher, ob die Entscheidung, Nachrichten zu verwenden oder nicht zu verwenden, in der Mitte des Projekts getroffen werden kann. Wenn Ereignismeldungen verwendet werden, würde ich sagen, muss auch das gesamte Objektdesign angepasst werden.
Bunkai.Satori
Ich stimme dir nicht zu. Wenn das gesamte Objektdesign gut gekapselt ist, sollte es flexibel genug sein, um in jeder Art von Framework verwendet zu werden. Ich war in der Lage, Kommunikationsmethoden in großen Projekten mit sehr wenig Arbeit auszutauschen, da jedes Stück gut gekapselt war.
Erick Robertson
7

Ich denke, Sie vergleichen hier Äpfel und Orangen. Polymorphismus wird überhaupt nicht durch Nachrichten ersetzt. Sie möchten wahrscheinlich, dass Ereignisse / Nachrichten lose gekoppelte Komponenten verbinden. Z.B. eine Nachricht von einer Entität zu senden, wenn eine Kollision auftritt, die Spielerwertung zu aktualisieren oder möglicherweise einen Soundeffekt auszulösen. Damit diese einzelnen Klassen die anderen Klassen nicht kennen und nur Nachrichten senden und / oder verarbeiten.

Aber Ihr Spiel wird höchstwahrscheinlich eine Update Schleife irgendwo haben , und da Sie haben die Update - Schleife, kann es leicht verwendet werden , um alle Spieleinheiten zu aktualisieren , die aktualisiert werden müssen , als auch für jeden Rahmen. Dies hindert Sie jedoch nicht daran, Messaging zu verwenden ...

Wenn Sie eine Struktur haben, in der Sie Spielentitäten hinzufügen / entfernen, können Sie sie genauso gut in Ihre Aktualisierungsschleife aufnehmen, anstatt in jedem Frame eine Aktualisierungsnachricht an sie zu senden. Rufen Sie das Update Ihrer Spielentitäten direkt auf, während Sie Messaging verwenden, um verschiedene Subsysteme Ihres Spiels zu verbinden. Ich mag auch das Signal / Slot-Konzept ( siehe qt Beispiel ) für ereignisähnliche Systeme.

Fazit: Es gibt keinen besseren Ansatz und sie sind auch nicht exklusiv.

bummzack
quelle
Hallo Bummzack. Endlich kam die erste Antwort. Vielen Dank dafür :-) Als ich Event Driven Architecture erwähnte, meinte ich ein MVC-System mit drei Schlüsselebenen: Appliaction, GameView, GameLogic. Die gesamte Kommunikation zwischen diesen Trhee würde über Messaging erfolgen. Dies unterscheidet sich erheblich von dem herkömmlichen System mit Aktualisierungsschleife. Jedes System hat eine andere Architektur, einige Vor- und Nachteile und unterschiedliche Leistungskosten. Ich glaube daher, dass man in einigen Bereichen etwas besser wäre. Nach einer guten Analyse sollten wir in der Lage sein zu schließen, welches besser ist.
Bunkai.Satori
3
Ich verstehe nicht, warum das anders ist? Sie benötigen irgendwo eine Update-Schleife, die wahrscheinlich den Controller aktualisiert, wenn Sie bei MVC bleiben möchten. Dann kann der Controller dem Modell und der Ansicht eine Nachricht senden. Da der Controller jedoch normalerweise Ansicht und Modell kennt , kann er sie auch direkt aktualisieren. Dies ersetzt jedoch keinen Polymorphismus. Ihre Fragen und Annahmen klingen sehr theoretisch. Vielleicht unterstützen Sie sie mit einem Beispielcode oder einigen Referenzen?
Bummzack
Das oben erwähnte Buch "Game Coding Complete" empfiehlt Event Messaging über direkte Aufrufe virtueller Methoden. Obwohl das Messaging-System komplexer aussieht, besteht sein Vorteil darin, dass nicht jedes Spielobjekt die Spielwelt überprüfen muss. Die Spielwelt wird nur einmal von der Spielelogik überprüft, und dann werden nur die Objekte angesprochen, die ihren Zustand ändern sollen. Dies ist ein Unterschied und kann zu Kosteneinsparungen führen. Wenn Sie entscheiden, dass Ihre Spielobjekte über Nachrichten kommunizieren, werden sie nicht in jedem Frame aufgerufen - daher schließen sich die beiden Ansätze gegenseitig aus.
Bunkai.Satori
1
Up-Voted für eine Antwort, die Tetrads Kommentare unter der ursprünglichen Frage widerspiegelt. @ Bunkai.Satori Die 'Spielwelt wird nur einmal überprüft' ist die Update-Schleife, alles, was aktualisiert werden muss, bekommt sie. Die Ereignismeldungen sind die selten erledigten, aber immer noch wichtigen Dinge in der Engine (PlayerDied, MonsterDied usw.), bei denen die Überprüfung jedes Frames in einer Update () - Schleife eine Verschwendung wäre, die jedoch höchstwahrscheinlich von der generiert werden Update () Schleife selbst.
James
1
Wenn Sie die zweite Ausgabe haben, lesen Sie das Kapitel Steuern der Hauptschleife. Es sollte in der 3. Ausgabe dasselbe heißen. Das sollte deine Frage wirklich beantworten.
Ray Dey
4

Dies begann als Kommentar zu Bummzacks Antwort, wurde aber lang.

Sofern Sie es nicht tatsächlich asynchron machen (Ereignisse in einem neuen Thread auslösen), erhalten Ihre Objekte das Memo weiterhin synchron. Angenommen, Ihr Ereignis-Dispatcher verwendet eine grundlegende Hash-Tabelle mit einer verknüpften Liste in einer Zelle. Die Reihenfolge ist die Reihenfolge, in der Objekte zu dieser Zelle hinzugefügt wurden.

Sofern Sie sich nicht aus irgendeinem Grund für die Verwendung von Funktionszeigern entscheiden, verwenden Sie weiterhin virtuelle Funktionsaufrufe, da jedes Objekt, das eine Nachricht erhält, IEventListener (oder wie auch immer Sie es nennen) implementieren muss. Ereignisse sind eine Abstraktion auf hoher Ebene, die Sie mithilfe von Polymorphismus erstellen.

Verwenden Sie Ereignisse, bei denen Sie eine Wäscheliste mit Methoden für verschiedene Ereignisse im Spiel aufrufen müssen, um verschiedene Systeme im Spiel zu synchronisieren, oder bei denen verschiedene Objekte und Systeme reagieren, sodass diese Ereignisse nicht klar definiert werden können oder Sie möchten weitere Reaktionen auf diese Ereignisse in der Zukunft hinzuzufügen.

Sie sind ein großartiges Werkzeug, aber wie Bummzack sagte, gehen Sie nicht davon aus, dass Polymorphismus und Ereignisse das gleiche Problem lösen.

michael.bartnett
quelle
Hallo Bearcdp, danke für deine Antwort. Das macht für mich Sinn. Ich denke an eines, das für Ereignismeldungen stimmt: Sagen wir, es gibt 200 Objekte in der Szene. Wenn Sie für alle Objekte Funktionsaufrufe pro Frame verwenden, müssen Sie alle 200 Objekte in jedem Frame auf Kollision überprüfen (ein Beispiel; natürlich können die Anrufintervalle verwaltet werden.) Bei Ereignisnachrichten wird die Spielwelt nur einmal untersucht. Bei 5 Kollisionen werden nur 5 Objekte durch Nachrichten über das Kollisionsereignis benachrichtigt, anstatt 200 Kollisionserkennungstests mit Einzelbildaufrufen. Was ist deine Meinung?
Bunkai.Satori
2
Untersuche die Spielwelt? was bedeutet das? Es müsste bedeuten, die gleichen 200 Überprüfungen durchzuführen, um die 5 zu isolieren, über die Nachrichten gesendet werden sollen. Mit dem virtuellen Funktionskonzept wird die Spielwelt auch nur einmal überprüft (die Funktion jedes Objekts wiederum) und wechselt dann nur zu den 5, die Statusänderungen benötigen ... ohne den Overhead eines Nachrichtensystems.
Steve H
1
Hören Sie Steve H, die Welt kollidiert nicht von selbst. Ich verwende Ereignisse hauptsächlich für Ereignisse auf hoher Ebene, wie z. B. PlayerJump, EnemyHit. Um die Effizienz der Kollisionsprüfung effizient zu gestalten, müssen Sie eine Datenstruktur auswählen, um den physischen Standort von Objekten in Ihrem Spiel zu organisieren, damit Sie priorisieren können, welche Objekte auf Kollision geprüft werden müssen und welche nicht. Nachdem Sie alle kollidierten Objektpaare ermittelt haben, können Sie ein Ereignis mit den relevanten Kollisionsdaten (den beiden Objekten Geschwindigkeits- / Positions- / Normaldaten usw.) auslösen.
michael.bartnett
Hallo Steve und Beardcp, danke für deine Kommentare. Was Sie geschrieben haben, macht Sinn. Es sieht so aus, als ob es viele mögliche Implementierungen des Event-Messaging-Systems geben kann. Es kann den reinen Ersatz des virtuellen Funktionskonzepts pro Frame geben, wie das oben erwähnte Buch sagt. Wie Sie sagen, kann das Messagingsystem jedoch auch mit dem Konzept der virtuellen Funktion pro Frame koexistieren.
Bunkai.Satori
Warum sagen Sie "aus irgendeinem Grund" in Bezug auf Funktionszeiger? So habe ich ein Ereignissystem implementiert, als ich eines von Grund auf neu geschrieben habe (ich arbeite in Sprachen mit erstklassigen Funktionen, aber es ist die gleiche Idee: Übergeben Sie die Funktion an das Ereignis-Hub-Objekt, und dieses Objekt ordnet Listener-Funktionen zu Ich frage mich, ob dieser Ansatz einen Nachteil hat.
Jhocking
2

Ich würde sagen, dass die Wahl des einen oder anderen ziemlich falsch ist. Einige Objekte müssen jeden Frame aufrufen, andere nicht. Wenn Sie ein Objekt , das Sie machen wollen , müssen Sie brauchen , um einen Anruf , um es jeden Frame machen machen. Ereignisse können diese Änderung nicht vornehmen. Das Gleiche gilt für alle zeitbasierten Physikobjekte - Sie müssen sie in jedem Frame aufrufen.

Ich rufe jedoch nicht jeden Frame meine Objektverwaltungsobjekte oder meine Benutzereingabeobjekte oder ähnliches auf. Virtuelle Massenaufrufe an jedes Objekt im Frame sind eine schreckliche Idee.

Das für ein bestimmtes Objekt verwendete Design sollte auf den Anforderungen dieser Objekte basieren und nicht auf einer Ideologie für das gesamte System.

Bearbeitet, um meinen ersten Satz klarer zu machen.

DeadMG
quelle
Hallo DeadMG, lassen Sie mich erklären: Im oben genannten Fall ist das Design in drei Hauptteile unterteilt: Anwendungsschicht (Hardwarezugriff), Spielelogik, Spielansicht. Was pro Frame-Basis gerendert wird, ist die Spielansicht. Wenn Game View jedoch eine Benutzereingabe aufzeichnet (z. B. Bremspedal beim Verfolgen des Spiels gedrückt), sendet es eine Nachricht "Car 2 Brake Pressed" zur Verarbeitung an Game Logic. Game Logic wertet diese Aktion aus, berechnet das Verhalten des Autos und sendet eine Nachricht an die Spielansicht: "Car 2 Block Tyres", "Car 2 Move to X, Y". Auf diese Weise muss nicht pro Frame überprüft werden, ob bei jedem Fahrzeug die Bremse gedrückt wurde.
Bunkai.Satori
@Bunkai: Sie haben also einige Designs, die ereignisgesteuert sind, und einige Designs, die als jeder Frame bezeichnet werden. Das stimmt ziemlich genau mit meiner Antwort überein.
DeadMG
Ich freue mich, Verständnis mit Ihnen zu finden, da diese Frage heute hier etwas kontrovers war :-)
Bunkai.Satori