Ich beginne mit meinem ersten "richtigen" Spielprojekt und bin unweigerlich auf einen Block gestoßen, um zu entscheiden, wie Spielkomponenten in XNA kommunizieren sollen.
Von früheren (Java) GUI-Programmierereignissen schienen Handler und Listener der richtige Weg zu sein. Ich hätte also eine Art Ereignisbus, der Ereignisregistrierungen und Klassen akzeptiert, die diese Ereignisse abonniert haben, mit Handlern, die sich darum kümmern. Zum Beispiel (Pseudocode):
class SpriteManager
Update(){
if(player.collidesWith(enemy)
// create new 'PlayerCollisionEvent'
}
class HUDManager
onPlayerCollisionEvent(){
// Update the HUD (reduce lives etc)
}
Ich bin mir jedoch nicht sicher, welches Code-Setup (in C #) erforderlich ist, um dies vollständig zu erreichen. Was verfolgt Ereignisse (eine Art Bus?) Und wie ist sie aufgebaut?
Es scheint auch viel über Game Services erwähnt zu werden, wobei Sie eine GameComponent in Ihrer Hauptklasse Game.cs registrieren und sie dann von einer beliebigen Stelle in Ihrem Code abrufen können, die einen Verweis auf das Hauptobjekt 'Game' enthält. Ich habe dies mit meinem SpriteBatch-Objekt versucht und es scheint sehr einfach zu sein. Ich kann jedoch nicht sehen, dass dies so flexibel ist wie ein Ereignismodell.
Nehmen wir zum Beispiel, wenn ein Feind stirbt. Wir möchten die Spielergebnisse aktualisieren. Mithilfe von Diensten kann ich einen Verweis auf mein in Game1 erstelltes und als Dienst hinzugefügtes StateManager-Objekt abrufen und dann "Punktzahl" auf den neuen Wert setzen. Ich hätte gedacht, dass ein "onEnemyDeath" -Ereignis, das von einer Vielzahl von Klassen unterschiedlich behandelt werden kann, aber durch eine Codezeile im entsprechenden Abschnitt "Erkennung feindlicher Todesfälle" ausgelöst wird, besser wäre, als jede erforderliche GameComponent einzeln zu wirken und dann irgendetwas aufzurufen Methoden sind erforderlich.
Oder sind diese Strategien etwas anderem unterlegen?
Mir ist klar, dass dies teilweise mein schlechtes C # -Wissen ist, ebenso wie Spielkommunikationsparadigmen, aber ich würde wirklich gerne diese grundlegende Sache richtig machen.
Aktualisieren
Nachdem ich mir Services angesehen habe, bin ich weniger überzeugt - es wird im Grunde genommen eine globale Variable weitergegeben (soweit ich weiß).
Update 2
Nachdem Sie sich dieses grundlegende Tutorial zur Ereignisbehandlung und zum Testen des Beispielcodes angesehen haben, scheint es, dass Ereignisse eine logische Wahl für das sind, was ich diskutiere. Aber ich kann nicht viel davon in den Beispielen verwenden, die ich gesehen habe. Gibt es einen offensichtlichen Grund, warum man nicht sollte?
quelle
Antworten:
Der Grund, warum Sie in C # nicht viel über Eventbusse finden, ist meiner Erfahrung nach, dass niemand außerhalb von Java so etwas als "Bus" bezeichnet. Häufigere Begriffe sind Nachrichtenwarteschlange, Ereignismanager, Signale / Slots, Veröffentlichen / Abonnieren usw.
Sie brauchen keines davon, um ein funktionierendes Spiel zu erstellen, aber wenn Sie mit diesem System vertraut sind, wird es Ihnen auch hier gute Dienste leisten. Leider kann dir niemand genau sagen, wie man einen macht, weil jeder sie ein bisschen anders rollt, wenn er sie überhaupt benutzt. (Ich zum Beispiel nicht.) Sie können mit einem einfachen
System.Collections.Generic.List<Event>
für die Warteschlange beginnen, wobei Ihre verschiedenen Ereignisse Unterklassen von Ereignis und eine Liste von Abonnenten für jeden Ereignistyp sind. Rufenhandle(this_event)
Sie für jedes Ereignis in der Warteschlange die Liste der Abonnenten ab und rufen Sie sie für jeden Abonnenten auf. Dann entfernen Sie es aus der Warteschlange. Wiederholen.Es ist wahrscheinlich nicht so flexibel, aber es ist einfacher zu debuggen. Ereignisse und Nachrichten sind schwierig, da sie die aufrufende Funktion von der aufgerufenen Funktion entkoppeln. Dies bedeutet, dass Ihre Aufrufstapel beim Debuggen nicht besonders hilfreich sind. Zwischenaktionen können dazu führen, dass etwas kaputt geht, was normalerweise funktioniert. Wenn sie nicht richtig angeschlossen sind, können die Dinge stillschweigend fehlschlagen , und so weiter. Die explizite Methode "Nehmen Sie eine Komponente und rufen Sie auf, was Sie darauf benötigen" funktioniert gut, wenn es darum geht, Fehler frühzeitig zu erkennen und klaren und expliziten Code zu haben. Es führt nur zu eng gekoppeltem Code und vielen komplexen Abhängigkeiten.
C # ist so ziemlich die gleiche Sprache wie Java. Was auch immer Sie in Java getan haben, kann in C # ausgeführt werden, nur mit unterschiedlicher Syntax. Wenn Sie Probleme beim Übersetzen eines Konzepts haben, liegt dies wahrscheinlich nur daran, dass Sie nur einen Java-spezifischen Namen dafür kennen.
quelle
Haben Sie versucht, nur einfache statische Ereignisse zu verwenden? Wenn Sie beispielsweise möchten, dass Ihre Punkteklasse weiß, wann ein Feind gestorben ist, würden Sie Folgendes tun:
Score.cs
EnemySpaceship.cs
SpaceshipDeathEventArgs.cs
quelle
Wenn Sie sich mit dem ereignisbasierten Ansatz nicht wohl fühlen, probieren Sie Artemis C # aus. Es handelt sich um ein Entity System-Framework, das auf http://t-machine.org/index.php/2007/09/03/entity-systems-are basiert -die-Zukunft-der-mmog-Entwicklung-Teil-1 /
Quelle: https://github.com/thelinuxlich/artemis_CSharp Beispielspiel: https://github.com/thelinuxlich/starwarrior_CSharp
quelle
Versuchen Sie, einen Ereignisaggregator wie diesen zu verwenden
quelle