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 Update
und ein Draw
Verfahren und rufen beide die GameScreen
‚s Update
und Draw
Methoden, die sich jede Komponente und Anruf durchlaufen Update
und 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 BackgroundManager
allen spezifischen Hintergründen suchen müssen . Sie haben nur ein ScrollingBackground
, ParallaxBackground
, StaticBackground
etc. , die alle aus einer derive Background
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, eine Sprite
Klasse als grundlegendes Sprite mit Textur- und Erweiterungsmethoden für Vektoren) und Zufallszahlengenerierung).
Sie würden keine BackgroundManager
Klasse mehr haben , sondern eine Background
Klasse, 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 Engine
in all Ihren GameScreen
Klassen behalten , um auch innerhalb einer GameScreen
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 befinden MainMenuScreen
, können Sie zum wechselnGameplayScreen
).
Dasselbe gilt für die Component
Klasse: Sie sollte die Referenz ihres übergeordneten Elements enthalten GameScreen
, um sowohl Zugriff auf die Engine
Klasse als auch auf das übergeordnete Element GameScreen
zu haben, um neue Komponenten hinzuzufügen (z. B. können Sie eine HUD-bezogene Klasse erstellen DrawableButton
, die eine
DrawableText
Komponente und eine StaticBackground
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 mit IService
s und lassen andere Klassen Dienste selbst hinzufügen ). ZB würde ich eine Camera2D
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.