Also habe ich darüber nachgedacht, wie monolithisch meine Klassen die meiste Zeit werden. Beispielsweise kann man in der Methode der Character
Klasse Jump
einen Verweis auf ein Soundeffektobjekt haben und dieses abspielen. Das ist an sich in Ordnung, aber wenn Physik, Animation, Kollision usw. berücksichtigt werden, wird die Sprungmethode riesig und die Character
Klasse hat viele Abhängigkeiten von vielen verschiedenen Dingen. Trotzdem kann dies in Ordnung sein. Was ist jedoch, wenn beim Springen des Charakters kein Ton mehr abgespielt werden soll? Jetzt müssen wir diese bestimmte Codezeile im Durcheinander des Jump
Codes finden und sie auskommentieren oder was auch immer.
Also .. ich dachte ..
Was wäre, wenn es stattdessen eine Art AudioSystem
Klasse gäbe und sie nur zufällige Ereignisse abonnieren würde, an denen sie in anderen Klassen interessiert ist ? Zum Beispiel kann die Character
Klasse ein Jumped
Ereignis haben (vermutlich auch statisch), das innerhalb der Character
Klasse in der Methode ausgelöst wird. Dann Character
würde die Klasse nichts über den kleinen Soundeffekt wissen, der gespielt wird, wenn der Charakter springt. Das AudioSystem
wäre nur eine riesige Klasse, in die sich der Programmierer zurückziehen könnte, um Soundeffekte mit bestimmten Ereignissen, die im Spiel auftreten, mithilfe statischer Ereignisse zu verbinden. Dann wird , wenn es zu groß bekommt könnte es um die Unterklassen wie getrennt werden EffectsAudioSystem
, BackgroundAudioSystem
, AmbientAudioSystem
und so weiter.
Dann könnte man in den Optionen für das Spiel ein Kontrollkästchen haben, um diese Art von Sounds zu aktivieren oder zu deaktivieren, und alles, was getan werden müsste, ist nur, dieses eine System mit einem einfachen und einzelnen Booleschen Flag zu deaktivieren. Diese Idee von Systemen könnte auch auf Dinge wie Physik, Animationen usw. ausgedehnt werden, bis zu dem Punkt, an dem die meisten Spielreaktionen, die sich aus Spieleraktionen ergeben, über diese ausgeklügelten und entkoppelten Systeme miteinander verbunden sind.
Okay, meine Frage mag etwas vage sein, aber wie klingt so etwas? Ich habe noch nie wirklich viel über diese Art von System gesprochen. Das ist alles in meinem Kopf, ohne dass bisher eine Codierung durchgeführt wurde. Vielleicht ist es eines dieser "theoretisch guten, aber nicht praktischen" Geschäfte. Würde diese Art von System mit einem größeren Spiel funktionieren oder würde es irgendwann zusammenbrechen und noch mehr zu einem Spaghetti-Chaos werden als das ursprüngliche System?
quelle
Antworten:
Nachrichten sind eine Hölle zum Debuggen und Verwalten. Theoretisch klingt es gut, aber wenn es einmal in die Praxis umgesetzt wird, wird es unordentlich, wenn viele doppelte Daten gesendet werden. Der Jump-Sound-Effekt benötigt am Ende viel mehr Daten, zum Beispiel die Position, Geschwindigkeit, das Material, auf dem sich der Charakter befindet, Sie nennen es, die Liste wird am Ende lang sein.
Entweder müssen Sie diese Daten sammeln und über ein ganz bestimmtes Ereignis / eine bestimmte Nachricht mit den darin kopierten Daten an den AudioManager senden, oder Sie senden einen Verweis auf das Zeichen in der Nachricht, damit der AudioManager auf beide Daten zugreifen kann Die Wege enden chaotisch, und jetzt muss der Audio-Manager einen Sound für das Material-Underground usw. auswählen.
Am Ende wird das spezifische Ereignis (das nur für diese Nachricht eine sehr spezifische Klasse ist) diese Klassen wieder sehr tief koppeln. Nicht viel gewonnen und am Ende haben Sie eine unordentliche große Liste sehr spezifischer Ereignisse / Klassen, die nur dem Zweck dienen, Daten zu versenden, die bereits vorhanden sind und möglicherweise veraltet sind und unter allen anderen Problemen mit doppelten Daten leiden .
Es wird also eine riesige Liste unnötiger Klassen geben, die eine tiefe Kopplung zwischen dem Charakter und dem AudioManager einführen müssen, außer jetzt ist sie über den gesamten Quellcode verteilt. Nicht nur in den Character- und AudioManager-Klassen.
Es ist immer noch eine gute Idee, Ihren Code zu entkoppeln, aber Nachrichten sind wirklich nur eine andere Art der tiefen Kopplung. Einige Codes müssen nur gekoppelt werden. Verwenden Sie den direktesten Weg, um sie zu koppeln. Überentwickeln Sie sie nicht.
quelle
Ich glaube nicht, dass ein Message-Passing-System über das Engineering hinausgeht. Tatsächlich kann es dramatisch einfacher sein, Dinge in der polnischen Phase zu erledigen. Du machst es richtig!
Was Sie beschrieben haben, ist genau das, was ich letztes Jahr für unser Global Game Jam-Spiel zusammengestellt habe. Ich war dafür verantwortlich, die SFX zu erstellen und zu bearbeiten und Musik, die ich und ein anderer Komponist geschrieben haben, auf eine Art und Weise in das Spiel zu integrieren, die nicht schlecht war.
Das Besondere an diesem Ansatz aus Audio-Sicht ist, dass Sie so viele weitere interessante Dinge mit Ihrem Sound tun können. Wenn Sie der Meinung sind, dass ein Soundeffekt in einem Spiel lediglich eine Audiodatei, Lautstärke und ein Schwenken ist, machen Sie es falsch.
Beispiel
Für unser Spiel waren Sie ein Dinosaurier, der ein Raumschiff flog, das auf Planeten lief, um Punkte zu sammeln. Wir haben in Flash gearbeitet, daher wurde keine datengesteuerte Infrastruktur benötigt. Der AudioManager war eine Klasse, die aus einer Reihe statischer Methoden bestand, deren einziger Zweck darin bestand, zu steuern, welche Geräusche als Reaktion auf ein Spielereignis auftraten.
Wenn ich es in C ++ schreiben würde, hätte es etwas länger gedauert, alle möglichen Verhaltensweisen zu abstrahieren, die Sounds haben könnten. Die Anforderungen für eine Nachricht, die das System darüber informiert, dass eine Aktion stattgefunden hat, wären nicht zu kompliziert. Es würde nur den Nachrichtentyp, das Ursprungsobjekt oder das betroffene Objekt, den Zugriff auf eine Art Spielstatuskontext und nicht viel mehr benötigen. Das Protokoll könnte mit den Anforderungen des Spiels wachsen. Wenn Sie all dies bei der Implementierung in Code tun (wie bei unserem schlechten GGJ-Code), haben Sie natürlich ein schlimmeres monolithisches Klassenproblem. Dies lässt sich jedoch leicht durch die Erstellung eines datengesteuerten Systems abmildern.
Wie auch immer, unser Spiel-Audiosystem hat auf verschiedene Nachrichten reagiert:
Spieler kollidiert mit dem Planeten: Dies würde einen Planetenexplosionsklang auslösen, der grundlegend genug ist. dann unmittelbar danach würde es den laufenden Kombinationszähler abfragen. Wenn es hoch genug wäre, würde es einen Soundeffekt einplanen, der ungefähr eine halbe Sekunde später gespielt wird, wenn der Dinosaurier ein Siegesgebrüll macht. Auch im Hintergrund wurde ein zufälliger Planetenpopulationswert berechnet (etwa 600 bis 3000 - ich habe keine Ahnung, warum dieser Bereich gewählt wurde, es war eine verlassene Spielmechanik und lag immer noch herum, damit ich das Audio interessant machen konnte). und so benutzte ich das, um die Lautstärke des entfernten Geräusches von Schreien zu skalieren (Planetenbürger, die einem vorzeitigen Schicksal begegnen).
Der Spieler hält die Leertaste für die Beschleunigung gedrückt : Nach Erhalt dieses Signals wurde ein kleiner "Whoosh" -Trieb abgespielt, gleichzeitig wurde jedoch ein Motorgeräusch mit niedriger Schleife über 1,5 Sekunden hochgefahren. Das Partikelsystem verwendete dies auch, um einen Emitter IIRC zu feuern
Der Spieler lässt die Leertaste zum Abbremsen los: Nachdem der Spieler die Leertaste losgelassen hatte, wusste das Audiosystem, dass die Motorschleife wieder heruntergefahren werden musste. Wenn ich mehr Zeit gehabt hätte, hätte ich gerne einen anderen Sound darüber gelegt, der eine Art jammerndes Geräusch war.
Der Spieler kollidiert mit der bösen Weltraummine: Weltraumminen sind schlecht, daher gibt es nicht nur einen metallischen Aufprallklang in Kombination mit einer Explosion (die nur in einem Klang zusammengefasst ist), sondern auch einen zufällig ausgewählten Dinosaurier-Bestürzungsklang, der abgespielt wird. Es ist wahrscheinlicher, dass Sie mehr "Weinen" wie Geräusche wählen, wenn die Gesundheit des Spielers abnimmt.
Ein bereits unterhaltsames Spiel wird zu einer Freude, wenn sein Soundtrack aktiv und dynamisch ist, selbst mit nur wenigen einfachen Verhaltensweisen, wie ich sie oben beschrieben habe. Ja, es gibt einige logistische Aspekte, um sicherzustellen, dass die richtigen Daten übergeben werden. Aber hey, BFD. Es wird alles andere als das Komplizierteste sein, was Sie im größeren Bereich des Spielcodes schreiben müssen.
Tatsächlich funktionieren FMOD und Wwise so. Sie haben keinen zentralen Nachrichten-Dispatcher, aber Sie veröffentlichen Ereignisse effektiv auf ihren zentralen Systemen und sie reagieren, indem sie einen Soundeffekt abspielen, der von einem Audio-Implementierer in einem Authoring-Tool vorab entworfen wurde. Stellen Sie sich vor, Sie geben Ihrem Spiel einen Live-DJ. Er sitzt und beobachtet, was los ist, und löst zum richtigen Zeitpunkt Soundclips aus, um die Dinge interessant zu halten, und mischt sie so, dass sie gut in die bereits vorhandene Audioumgebung passen.
[BEARBEITEN] Ich sehe auch, dass Sie dieses C # markiert haben. Ist das XNA und wenn ja, verwenden Sie XACT? Wenn Sie XNA verwenden, sollten Sie XACT verwenden.
quelle
EventManager->dispatch("Sound:PlayerJump")
undsoundSystem->playFMODEvent("/MyGame/Player/Jump")
.Ich stimme Maik Semder zu, dass ein Nachrichtenübermittlungssystem (vorerst sowieso) möglicherweise überentwickelt ist.
Soweit ich weiß, sieht Ihre Klasse derzeit wie die "monolithische Klasse" von Björn aus, wie in "Eine monolithische Klasse" hier zu sehen ist .
Ich schlage vor, Sie lesen diesen Artikel, und obwohl ein Vollkomponentensystem vorerst übertrieben wäre, sollte dies Ihnen eine gute Möglichkeit bieten, Ihr Verhalten zu abstrahieren und möglicherweise zu einem komplexeren zu wechseln, wenn Sie "Den Rest aufteilen" lesen Lösung. Es gibt Ihnen eine gute Basis, um trotzdem zu beginnen.
quelle