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 Update
et une Draw
méthode à la fois et les appels GameScreen
« s Update
et des Draw
méthodes qui se passent par chaque composant et appel Update
et 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 BackgroundManager
tous les arrière-plans spécifiques. Vous avez juste un ScrollingBackground
, ParallaxBackground
, StaticBackground
, etc. , qui tous proviennent d'une Background
classe.
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 FrameRateDisplayer
utilitaire de débogage, une Sprite
classe 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 BackgroundManager
classe, mais une Background
classe 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 Engine
au sein de toutes vos GameScreen
classes, pour pouvoir ajouter de nouveaux écrans même au sein d'une GameScreen
classe (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 Component
classe: elle doit contenir la référence de son parent GameScreen
, pour avoir à la fois accès à la Engine
classe et à son parent GameScreen
pour ajouter de nouveaux composants (par exemple, vous pouvez créer une classe liée au HUD appelée DrawableButton
qui contient un
DrawableText
composant et un StaticBackground
composant).
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 Engine
classe (vous gardez simplement une liste de IService
s et laissez les autres classes ajouter des services elles-mêmes ). Par exemple, je garderais un Camera2D
composant 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.