Ich mache einen kleinen Dungeon-Crawler im Weltraum und würde gerne einen Rat hören, wie man das Backend der Engine schöner macht. Grundsätzlich basiert derzeit alles auf einer Menge Manager:
- BackgroundManager: Verfügt über eine
AddBackground(image, parallax)
Methode zum Erstellen cooler Hintergrundeffekte. - ConfigManager: Liest / erstellt die Konfigurationsdatei und enthält auch die aus dieser Konfigurationsdatei gelesenen Daten.
- DrawManager: hat
Draw(sprite)
Methode Zeug auf den Bildschirm zu zeichnen, und solche SachenSetView(view)
,GetView()
usw. - EntityManager: Enthält alle aktiven Entitäten und verfügt über Methoden zum Hinzufügen, Entfernen und Suchen von Entitäten.
- DungeonManager (eigentlich ein GridManager genannt, aber das ist der Einfachheit halber): hat Methoden wie
GenerateDungeon()
,PlaceEnemies()
,PlaceFinish()
usw.
Jetzt bin ich noch nicht einmal auf halber Strecke und liste alle meine Manager auf. Ich denke, das muss sich ändern. Mein Spiel basiert auch auf Bildschirmen, was es ärgerlicher macht, weil ich nicht die Hälfte der Dinge benötige, die meine Manager verwalten, zum Beispiel das Hauptmenü (ich benötige keine Physik / Entities / Dungeons in meinem Hauptmenü) !)
Jetzt dachte ich darüber nach, die Manager nicht statisch zu machen und meinem ScreenMainGame eine Instanz aller spielspezifischen Manager zu geben. Aber das macht das Anrufen / Erhalten von Informationen zu den Managern zu einem großen Chaos ... Wenn ich zum Beispiel meinen Kerker von einem Ort ziehen wollte, an dem er nicht ist ScreenMainGame.Draw()
, müsste ich das tun ...
((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()
Das ist wirklich hässlich.
Also, liebe Spieleentwickler, hat jemand von euch eine Idee, wie man dieses Durcheinander löst? Ich wäre dankbar!
quelle
Antworten:
Was ist mit einem komponentenbasierten Motor ?
Sie hätten eine Hauptklasse mit dem Namen
Engine
, die eine Liste von enthältGameScreens
, die selbst eine Liste von enthältComponents
.Der Motor verfügt über ein
Update
und einDraw
Verfahren und rufen beide dieGameScreen
‚sUpdate
undDraw
Methoden, die sich jede Komponente und Anruf durchlaufenUpdate
undDraw
.So präsentiert, stimme ich zu, dass es sich nach einem schlechten und sich wiederholenden Design anhört. Aber glauben Sie mir, mein Code wurde durch die Verwendung eines komponentenbasierten Ansatzes viel sauberer als bei all meinen alten Manager- Klassen.
Es ist viel einfacher, solchen Code zu pflegen, da Sie nur eine große Klassenhierarchie durchlaufen und nicht nach
BackgroundManager
allen spezifischen Hintergründen suchen müssen . Sie haben nur einScrollingBackground
,ParallaxBackground
,StaticBackground
etc. , die alle aus einer deriveBackground
Klasse.Sie werden schließlich eine ziemlich solide Engine aufbauen, die Sie in all Ihren Projekten mit einer Vielzahl häufig verwendeter Komponenten und Hilfsmethoden wiederverwenden können (z. B.
FrameRateDisplayer
als Debugging-Dienstprogramm, eineSprite
Klasse als grundlegendes Sprite mit Textur- und Erweiterungsmethoden für Vektoren) und Zufallszahlengenerierung).Sie würden keine
BackgroundManager
Klasse mehr haben , sondern eineBackground
Klasse, die sich selbst verwalten würde.Wenn dein Spiel beginnt, musst du nur Folgendes tun:
Und das wars für deinen Spielstartcode.
Dann für den Hauptmenübildschirm:
Sie bekommen die allgemeine Vorstellung.
Sie würden auch die Referenz der
Engine
in all IhrenGameScreen
Klassen behalten , um auch innerhalb einerGameScreen
Klasse neue Bildschirme hinzufügen zu können (z. B. wenn der Benutzer auf die Schaltfläche StartGame klickt , während Sie sich in Ihrer befindenMainMenuScreen
, können Sie zum wechselnGameplayScreen
).Dasselbe gilt für die
Component
Klasse: Sie sollte die Referenz ihres übergeordneten Elements enthaltenGameScreen
, um sowohl Zugriff auf dieEngine
Klasse als auch auf das übergeordnete ElementGameScreen
zu haben, um neue Komponenten hinzuzufügen (z. B. können Sie eine HUD-bezogene Klasse erstellenDrawableButton
, die eineDrawableText
Komponente und eineStaticBackground
Komponente enthält).Anschließend können Sie sogar andere Entwurfsmuster anwenden, z. B. das "Dienstentwurfsmuster" (bei dem der genaue Name nicht bekannt ist), in dem Sie verschiedene nützliche Dienste in Ihrer
Engine
Klasse aufbewahren können (Sie führen einfach eine Liste mitIService
s und lassen andere Klassen Dienste selbst hinzufügen ). ZB würde ich eineCamera2D
Komponente über mein gesamtes Projekt als Dienst behalten , um ihre Transformation beim Zeichnen anderer Komponenten anzuwenden. Dies vermeidet, dass es überall als Parameter übergeben werden muss.Zusammenfassend kann gesagt werden, dass es sicherlich andere bessere Designs für einen Motor gibt, aber ich fand den von diesem Link vorgeschlagenen Motor sehr elegant, äußerst wartungsfreundlich und wiederverwendbar. Ich persönlich würde es zumindest empfehlen, es zu versuchen.
quelle
GameComponent
und Dienste. Keine Notwendigkeit für eine separateEngine
Klasse.Sie möchten Ihren Code in Komponenten und Services unterteilen. XNA hat bereits eine integrierte Unterstützung für diese.
Siehe diesen Artikel auf
GameComponents
und Dienstleistungen. Lesen Sie dann diese Antwort zur Verwendung von Diensten in XNA und diese allgemeinere Antwort zu Diensten in einer beliebigen Sprache.quelle
Nur weil sie statisch oder global sind, müssen sie nicht immer geladen / initialisiert werden. Verwenden Sie ein Singleton-Muster, und ermöglichen Sie den Managern, bei Bedarf freigegeben und erneut geladen zu werden.
quelle