¿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 Update
y un Draw
método y ambos llaman los GameScreen
's Update
y los Draw
métodos, que pasan por cada componente y llaman Update
y 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 BackgroundManager
todos los diferentes fondos específicos. Sólo tienes una ScrollingBackground
, ParallaxBackground
, StaticBackground
, etc, todos ellos derivados de una Background
clase.
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, FrameRateDisplayer
como una utilidad de depuración, una Sprite
clase 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 BackgroundManager
clase, sino una Background
clase 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 Engine
dentro de todas sus GameScreen
clases, para poder agregar nuevas pantallas incluso dentro de una GameScreen
clase (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 Component
clase: debe contener la referencia de su padre GameScreen
, para tener acceso tanto a la Engine
clase como a su padre GameScreen
para agregar nuevos componentes (por ejemplo, puede hacer una clase relacionada con HUD llamada DrawableButton
que contiene un
DrawableText
componente y un StaticBackground
componente).
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 Engine
clase (simplemente mantiene una lista de IService
sy permite que otras clases agreguen servicios ellos mismos) ) Por ejemplo, mantendría un Camera2D
componente 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.