¿Qué pasa con un motor basado en componentes ?
Tendría una clase principal llamada Engine, que mantendría una lista de GameScreens, que ellos mismos tendrían una lista de Components.
El motor tiene un Updatey un Drawmétodo y ambos llaman los GameScreen's Updatey los Drawmétodos, que pasan por cada componente y llaman Updatey Draw.
Presentado así, estoy de acuerdo en que suena como un diseño pobre y repetitivo. Pero créanme, mi código se volvió mucho más limpio mediante el uso de un enfoque basado en componentes que con todas mis antiguas clases de administrador .
También es mucho más simple mantener dicho código, ya que solo está pasando por una gran jerarquía de clases y no tiene que buscar BackgroundManagertodos los diferentes fondos específicos. Sólo tienes una ScrollingBackground, ParallaxBackground, StaticBackground, etc, todos ellos derivados de una Backgroundclase.
Eventualmente construirá un motor bastante sólido que puede reutilizar en todos sus proyectos con muchos componentes y métodos auxiliares de uso frecuente (por ejemplo, FrameRateDisplayercomo una utilidad de depuración, una Spriteclase como sprite básico con una textura y métodos de extensión para vectores y generación de números aleatorios).
Ya no tendrías una BackgroundManagerclase, sino una Backgroundclase que se administraría sola.
Cuando comienza tu juego, todo lo que tienes que hacer es básicamente esto:
// 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();
Y eso es todo para el código de inicio del juego.
Luego, para la pantalla del menú 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);
}
}
}
Tienes la idea general.
También mantendría la referencia de Enginedentro de todas sus GameScreenclases, para poder agregar nuevas pantallas incluso dentro de una GameScreenclase (por ejemplo, cuando el usuario hace clic en el botón StartGame mientras está dentro de su MainMenuScreen, puede hacer la transición a GameplayScreen).
Lo mismo ocurre con la Componentclase: debe contener la referencia de su padre GameScreen, para tener acceso tanto a la Engineclase como a su padre GameScreenpara agregar nuevos componentes (por ejemplo, puede hacer una clase relacionada con HUD llamada DrawableButtonque contiene un
DrawableTextcomponente y un StaticBackgroundcomponente).
Incluso puede aplicar otros patrones de diseño después de eso, como el "patrón de diseño de servicios" (no estoy seguro sobre el nombre exacto) donde puede mantener diferentes servicios útiles dentro de su Engineclase (simplemente mantiene una lista de IServicesy permite que otras clases agreguen servicios ellos mismos) ) Por ejemplo, mantendría un Camera2Dcomponente en todo mi proyecto como un servicio para aplicar su transformación al dibujar otros componentes. Esto evita tener que pasarlo como parámetro en todas partes.
En conclusión, ciertamente puede haber otros mejores diseños para un motor, pero el motor propuesto por este enlace me pareció muy elegante, extremadamente fácil de mantener y reutilizar. Yo personalmente recomendaría al menos intentarlo.