Qu'en est-il d'un moteur basé sur des composants ?
Vous auriez une classe principale nommée Engine, qui conserverait une liste de GameScreens, qui détiendrait elle-même une liste de Components.
Le moteur a une Updateet une Drawméthode à la fois et les appels GameScreen« s Updateet des Drawméthodes qui se passent par chaque composant et appel Updateet Draw.
Présenté comme ça, je conviens que cela ressemble à un design pauvre et répétitif. Mais croyez-moi, mon code est devenu beaucoup plus propre en utilisant une approche basée sur les composants qu'avec toutes mes anciennes classes de gestionnaire .
Il est également beaucoup plus simple de conserver un tel code, car vous passez simplement par une grande hiérarchie de classes et vous n'avez pas à parcourir BackgroundManagertous les arrière-plans spécifiques. Vous avez juste un ScrollingBackground, ParallaxBackground, StaticBackground, etc. , qui tous proviennent d'une Backgroundclasse.
Vous finirez par créer un moteur assez solide que vous pouvez réutiliser sur tous vos projets avec de nombreux composants et méthodes d'assistance fréquemment utilisés (par exemple, un FrameRateDisplayerutilitaire de débogage, une Spriteclasse comme sprite de base avec une texture et des méthodes d'extension pour les vecteurs). et génération de nombres aléatoires).
Vous n'auriez plus de BackgroundManagerclasse, mais une Backgroundclasse qui se gérerait à la place.
Lorsque votre jeu démarre, tout ce que vous avez à faire est essentiellement:
// 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();
Et c'est tout pour votre code de démarrage de jeu.
Ensuite, pour l'écran du menu principal:
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);
}
}
}
Vous avez l'idée générale.
Vous conserveriez également la référence de la Engineau sein de toutes vos GameScreenclasses, pour pouvoir ajouter de nouveaux écrans même au sein d'une GameScreenclasse (par exemple, lorsque l'utilisateur clique sur le bouton StartGame dans votre MainMenuScreen, vous pouvez passer au GameplayScreen).
Il en va de même pour la Componentclasse: elle doit contenir la référence de son parent GameScreen, pour avoir à la fois accès à la Engineclasse et à son parent GameScreenpour ajouter de nouveaux composants (par exemple, vous pouvez créer une classe liée au HUD appelée DrawableButtonqui contient un
DrawableTextcomposant et un StaticBackgroundcomposant).
Vous pouvez même appliquer d'autres modèles de conception après cela, comme le "modèle de conception de service" (pas sûr du nom exact) où vous pouvez conserver différents services utiles dans votre Engineclasse (vous gardez simplement une liste de IServices et laissez les autres classes ajouter des services elles-mêmes ). Par exemple, je garderais un Camera2Dcomposant sur tout mon projet en tant que service pour appliquer sa transformation lors du dessin d'autres composants. Cela évite d'avoir à le passer partout en paramètre.
En conclusion, il peut certainement y avoir d'autres meilleures conceptions pour un moteur, mais j'ai trouvé le moteur proposé par ce lien très élégant, extrêmement facile à entretenir et réutilisable. Je recommanderais personnellement au moins de l'essayer.