Ich habe mich mit den Grundlagen einer Java-Game-Engine beschäftigt und bin an dem Punkt angelangt, an dem ich bereit bin, ein Event Manager-System hinzuzufügen.
Ich weiß theoretisch , was ein Event Manager tun sollte: Erlauben Sie Objekten, sich für bestimmte Ereignisse zu "registrieren", und senden Sie das Ereignis an die "registrierten" Listener, wenn der Event Manager über ein Ereignis benachrichtigt wird. Ich bin ratlos darüber, wie ich mit der Implementierung beginnen soll.
Ich konnte online nichts über die Implementierung eines Ereignissystems von Grund auf finden. Daher suche ich nach Informationen zu den Best Practices in diesem Fall - was ich tun sollte und was nicht .
Ist es zum Beispiel wirklich notwendig, dass jedes meiner Spielobjekte ein EventManager
Feld hat? Da alle meine Spielobjekte von einer einzelnen abstrakten übergeordneten Klasse erben, sollte ich in der Lage sein, eine statische Referenz zu verwenden, damit nur eine Instanz des Event Managers von allen Spielobjekten gemeinsam genutzt wird. Mit dem Applet mache ich etwas Ähnliches, mit dem ich bereits jedes Objekt rendere.
Ich nehme an, ich müsste für jedes mögliche abonnierte Ereignis eine Art Sammlung verwalten - Spielobjekte nach Bedarf hinzufügen und aus der Liste entfernen. Ich denke, es sollte möglich sein, eine Warteschlange mit Ereignissen zu erstellen, die gesendet werden müssen. In diesem Fall könnte ich einfach "EventManager.Update ()" zur Hauptspielschleife hinzufügen und die Update()
Methode die Ereignisse senden lassen, die am Ende aufgetreten sind jedes Rahmens. Schließlich hätte jedes Objekt eine HandleEvent(Event e)
Methode, die es dann analysieren und entsprechend beantworten könnte.
Klingt dies nach der richtigen Richtung für die Implementierung eines solchen Systems, oder bin ich weit vom Kurs entfernt und / oder vermisse etwas ganz Offensichtliches?
Antworten:
Dies kann so einfach sein, wie Sie möchten.
Versuchen Sie nicht herauszufinden, was ein Eventmanager tun sollte - finden Sie heraus, wozu Sie ihn benötigen. Der Rest sollte von dort folgen oder zumindest einige spezifischere Fragen vorschlagen.
quelle
Die drei wesentlichen Methoden, die ein Ereignissystem benötigt, sind eine addListener () -Methode, eine removeListener () -Methode und eine Methode zum dispatchEvent (). Das heißt, ein Methodenobjekt wird zum Registrieren für ein Ereignis verwendet, ein Methodenobjekt zum Aufheben der Registrierung und eine Methode zum tatsächlichen Senden eines Ereignisses an alle Listener. Alles andere ist Soße.
Wie Sie bemerken, benötigen Sie sicherlich eine Art Datenstruktur, um die registrierten Listener im Auge zu behalten. Der einfachste Ansatz wäre ein assoziatives Array (Wörterbuch oder ein Objekt in JavaScript), das einem Ereignis einen Vektor (oder einfach ein Array, abhängig von der Sprache) zuordnet. Dieser Vektor ist eine Liste aller registrierten Listener. Fügen Sie der Liste Listener hinzu oder entfernen Sie sie mit den Methoden add / removeListener ().
Das Senden eines Ereignisses in dispatchEvent () kann so einfach wie das Durchlaufen des Vektors sein. Sie können den Versand komplexer gestalten, indem Sie die Priorität von Ereignissen oder was auch immer sortieren. Machen Sie sich darüber jedoch keine Sorgen, bis Sie sie benötigen. In vielen Fällen brauchen Sie es nicht.
DispatchEvent () hat eine kleine Nuance, wenn Sie überlegen, welche Daten mit dem Ereignis weitergegeben werden sollen. Auf der einfachsten Ebene geben Sie möglicherweise keine zusätzlichen Daten weiter. Der Hörer muss nur wissen, dass ein Ereignis passiert ist. Bei den meisten Ereignissen sind jedoch zusätzliche Daten enthalten (z. B. wo das Ereignis aufgetreten ist), damit dispatchEvent () einige Parameter akzeptiert und weitergibt.
Es gibt viele Möglichkeiten, allen Spielobjekten einen Verweis auf die EventManager-Klasse zu geben. Eine statische Referenz ist sicherlich eine Möglichkeit; Ein anderer ist mit einem Singleton. Beide Ansätze sind jedoch ziemlich unflexibel, sodass die meisten Leute hier entweder einen Service Locator oder eine Abhängigkeitsinjektion empfehlen. Ich habe eine Abhängigkeitsinjektion durchgeführt. Das bedeutet zwar ein separates EventManager-Feld für jedes Objekt, was Sie anscheinend vermeiden möchten, aber ich bin mir nicht sicher, warum dies ein Problem ist. Es ist nicht so, dass das Speichern einer Reihe von Zeigern viel Aufwand bedeutet.
quelle
Die Grundlagen der Ereignisbehandlung sind ziemlich einfach.
Wenn Sie dies wissen (aber nicht wissen, wie es in Java implementiert wird), ist es leicht zu verstehen, dass Sie einige Handler (Funktionen zum Behandeln der Ereignisse) benötigen und diese einem Array (mit Zeigern in C) hinzufügen, das mit einem Ereignisnamen gepaart ist. Sobald Sie ein Ereignis auslösen, speichern Sie den Namen des ausgelösten Ereignisses und seine Argumente in einem Stapel. Dies wird als Ereignispool bezeichnet.
Dann haben Sie einen Ereignis-Digest (eine einfache Schleife), der das erste Ereignis in diesem Stapel auslöst, versucht, einen Handler dafür zu finden, und ihn, falls vorhanden, mit den Parametern ausführt.
Natürlich kann diese Ereignisübersicht jederzeit ausgelöst werden, beispielsweise einmal pro Frame, nachdem Sie Ihre
Update()
Funktion aufgerufen haben .quelle
Verwenden Sie für das EventManager-Feld eine statische Variable. Ein Singleton für den EventManager wäre auch eine gute Idee.
Ihr Ansatz klingt gut, aber vergessen Sie nicht, ihn threadsicher zu machen.
Es ist gut, E / A-Ereignisse vor oder nach dem "GameEvent" auszuführen, sodass in einem Frame jedes "GameEvent" dieselben Daten verarbeitet.
quelle