Was ist mit einem komponentenbasierten Motor ?
Sie hätten eine Hauptklasse mit dem Namen Engine, die eine Liste von enthält GameScreens, die selbst eine Liste von enthält Components.
Der Motor verfügt über ein Updateund ein DrawVerfahren und rufen beide die GameScreen‚s Updateund DrawMethoden, die sich jede Komponente und Anruf durchlaufen Updateund Draw.
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 BackgroundManagerallen spezifischen Hintergründen suchen müssen . Sie haben nur ein ScrollingBackground, ParallaxBackground, StaticBackgroundetc. , die alle aus einer derive BackgroundKlasse.
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. FrameRateDisplayerals Debugging-Dienstprogramm, eine SpriteKlasse als grundlegendes Sprite mit Textur- und Erweiterungsmethoden für Vektoren) und Zufallszahlengenerierung).
Sie würden keine BackgroundManagerKlasse mehr haben , sondern eine BackgroundKlasse, die sich selbst verwalten würde.
Wenn dein Spiel beginnt, musst du nur Folgendes tun:
// when declaring variables:
Engine engine;
// when initializing:
engine = new Engine();
engine.Initialize();
engine.LoadContent();
engine.AddGameScreen(new MainMenuScreen());
// when updating:
engine.Update();
// when drawing:
engine.Draw();
Und das wars für deinen Spielstartcode.
Dann für den Hauptmenübildschirm:
class MainMenuScreen : MenuScreen // where MenuScreen derives from the GameScreen class
{
const int ENEMY_COUNT = 10;
StaticBackground background;
Player player;
List<Enemy> enemies;
public override void Initialize()
{
background = new StaticBackground();
player = new Player();
enemies = new List<Enemy>();
base.AddComponent(background); // defined within the GameScreen class
base.AddComponent(player);
for (int i = 0; i < ENEMY_COUNT; ++i)
{
Enemy newEnemy = new Enemy();
enemies.Add(newEnemy);
base.AddComponent(newEnemy);
}
}
}
Sie bekommen die allgemeine Vorstellung.
Sie würden auch die Referenz der Enginein all Ihren GameScreenKlassen behalten , um auch innerhalb einer GameScreenKlasse neue Bildschirme hinzufügen zu können (z. B. wenn der Benutzer auf die Schaltfläche StartGame klickt , während Sie sich in Ihrer befinden MainMenuScreen, können Sie zum wechselnGameplayScreen ).
Dasselbe gilt für die ComponentKlasse: Sie sollte die Referenz ihres übergeordneten Elements enthalten GameScreen, um sowohl Zugriff auf die EngineKlasse als auch auf das übergeordnete Element GameScreenzu haben, um neue Komponenten hinzuzufügen (z. B. können Sie eine HUD-bezogene Klasse erstellen DrawableButton, die eine
DrawableTextKomponente und eine StaticBackgroundKomponente 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 EngineKlasse aufbewahren können (Sie führen einfach eine Liste mit IServices und lassen andere Klassen Dienste selbst hinzufügen ). ZB würde ich eine Camera2DKomponente ü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.