Gute Frage! Bevor ich zu den spezifischen Fragen komme, die Sie gestellt haben, sage ich: Unterschätzen Sie nicht die Macht der Einfachheit. Tenpn ist richtig. Denken Sie daran, dass Sie mit diesen Ansätzen nur eine elegante Möglichkeit finden, einen Funktionsaufruf aufzuschieben oder den Anrufer vom Angerufenen zu entkoppeln. Ich kann Coroutinen als einen überraschend intuitiven Weg empfehlen, um einige dieser Probleme zu lindern, aber das ist ein wenig abseits des Themas. Manchmal ist es besser, nur die Funktion aufzurufen und damit zu leben, dass Entität A direkt mit Entität B gekoppelt ist. Siehe YAGNI.
Das heißt, ich habe das Signal / Slot-Modell in Kombination mit der einfachen Nachrichtenübermittlung verwendet und war damit zufrieden. Ich habe es in C ++ und Lua für einen ziemlich erfolgreichen iPhone-Titel verwendet, der einen sehr engen Zeitplan hatte.
Wenn für den Signal- / Slot-Fall die Entität A als Reaktion auf die Aktivität der Entität B etwas tun soll (z. B. eine Tür aufschließen, wenn etwas stirbt), kann die Entität A das Todesereignis der Entität B direkt abonnieren. Oder möglicherweise abonniert die Entität A jede Entität aus einer Gruppe von Entitäten, erhöht bei jedem ausgelösten Ereignis einen Zähler und schließt die Tür auf, nachdem N von ihnen gestorben sind. Außerdem sind "Gruppe von Entitäten" und "N von ihnen" typischerweise Designer, die in den Ebenendaten definiert sind. (Nebenbei bemerkt ist dies ein Bereich, in dem Coroutinen wirklich glänzen können, z. B. WaitForMultiple ("Dying", entA, entB, entC); door.Unlock ();)
Das kann jedoch umständlich werden, wenn es um Reaktionen geht, die eng mit dem C ++ - Code verknüpft sind, oder um kurzlebige Spielereignisse: Verursachen von Schaden, Nachladen von Waffen, Debuggen und spielerbasiertes ortsbezogenes KI-Feedback. Hier kann das Weiterleiten von Nachrichten die Lücken füllen. Es läuft im Wesentlichen auf etwas hinaus: "Sagen Sie allen Einheiten in diesem Bereich, dass sie in 3 Sekunden Schaden erleiden sollen." Oder: "Wenn Sie die Physik abschließen, um herauszufinden, wen ich erschossen habe, sagen Sie ihnen, dass sie diese Skriptfunktion ausführen sollen." Es ist schwierig herauszufinden, wie dies mit Publish / Subscribe oder Signal / Slot funktioniert.
Dies kann leicht zu viel sein (im Vergleich zu Tenpns Beispiel). Es kann auch ineffizient sein, wenn Sie viel Action haben. Trotz seiner Nachteile passt dieser Ansatz von "Nachrichten und Ereignissen" sehr gut zum geskripteten Spielcode (z. B. in Lua). Der Skriptcode kann seine eigenen Nachrichten und Ereignisse definieren und darauf reagieren, ohne dass sich der C ++ - Code darum kümmert. Und der Skriptcode kann auf einfache Weise Nachrichten senden, die C ++ - Code auslösen, z. B. das Ändern von Pegeln, das Abspielen von Sounds oder sogar das Festlegen des Schadens, den die TakeDamage-Nachricht verursacht, durch eine Waffe. Es hat mir eine Menge Zeit gespart, weil ich nicht ständig mit Luabind herumalbern musste. Und so konnte ich meinen gesamten Luabind-Code an einem Ort aufbewahren, da nicht viel davon vorhanden war. Wenn richtig gekoppelt,
Außerdem ist meine Erfahrung mit Anwendungsfall Nr. 2, dass es besser ist, ihn als Ereignis in die andere Richtung zu behandeln. Anstatt nach dem Zustand der Entität zu fragen, sollten Sie ein Ereignis auslösen / eine Nachricht senden, wenn der Zustand eine signifikante Änderung vornimmt.
In Bezug auf die Schnittstellen hatte ich übrigens drei Klassen, um all dies zu implementieren: EventHost, EventClient und MessageClient. EventHosts erstellen Slots, EventClients abonnieren sie / stellen eine Verbindung zu ihnen her, und MessageClients ordnen einen Delegaten einer Nachricht zu. Beachten Sie, dass das Delegiertenziel eines MessageClient nicht unbedingt dasselbe Objekt sein muss, dem die Zuordnung gehört. Mit anderen Worten, MessageClients können nur existieren, um Nachrichten an andere Objekte weiterzuleiten. FWIW, die Host / Client-Metapher ist irgendwie unangemessen. Quelle / Senke könnten bessere Konzepte sein.
Tut mir leid, ich bin ein bisschen dort herumgewandert. Es ist meine erste Antwort :) Ich hoffe, es hat Sinn ergeben.