Che dire di un motore basato su componenti ?
Avresti una classe principale denominata Engine, che manterrebbe un elenco di GameScreens, che a sua volta avrebbe un elenco di Components.
Il motore ha un Updatee un Drawmetodo ed entrambi chiamano GameScreen"s" Updatee Drawmetodi, che a loro volta passano attraverso ogni componente e chiamano Updatee Draw.
Presentato in questo modo, concordo sul fatto che sembra un design scadente e ripetitivo. Ma credimi, il mio codice è diventato molto più pulito utilizzando un approccio basato sui componenti rispetto a tutte le mie vecchie classi manager .
È anche molto più semplice mantenere tale codice, poiché stai attraversando una gerarchia di grandi classi e non devi cercare BackgroundManagertutti i diversi sfondi specifici. Devi solo una ScrollingBackground, ParallaxBackground, StaticBackground, ecc, che derivano tutte da una Backgroundclasse.
Alla fine costruirai un motore piuttosto solido che puoi riutilizzare su tutti i tuoi progetti con molti componenti e metodi di supporto utilizzati di frequente (ad esempio FrameRateDisplayercome utilità di debug, una Spriteclasse come uno sprite di base con una trama e metodi di estensione per i vettori e generazione di numeri casuali).
Non avresti più una BackgroundManagerclasse, ma una Backgroundclasse che si gestirà da sola.
All'inizio del gioco, tutto ciò che devi fare è sostanzialmente questo:
// 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();
E questo è tutto per il codice di inizio del gioco.
Quindi, per la schermata del menu principale:
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);
}
}
}
Hai un'idea generale.
Manterrai anche il riferimento Engineall'interno di tutte le tue GameScreenclassi, per poter aggiungere nuove schermate anche all'interno di una GameScreenclasse (ad es. Quando l'utente fa clic sul pulsante StartGame mentre sei all'interno di te MainMenuScreen, puoi passare a GameplayScreen).
Lo stesso vale per la Componentclasse: dovrebbe contenere il riferimento del suo genitore GameScreen, per avere sia l'accesso alla Engineclasse sia il suo genitore GameScreenper aggiungere nuovi componenti (ad esempio puoi creare una classe relativa a HUD chiamata DrawableButtonche contiene un
DrawableTextcomponente e un StaticBackgroundcomponente).
Successivamente puoi anche applicare altri modelli di progettazione, come il "modello di progettazione del servizio" (non sono sicuro del nome esatto) in cui puoi mantenere diversi servizi utili all'interno della tua Engineclasse (semplicemente tieni un elenco di se IServicelasci che altre classi aggiungano servizi da soli ). ad es. manterrei un Camera2Dcomponente su tutto il mio progetto come servizio per applicare la sua trasformazione quando disegna altri componenti. Questo evita di doverlo passare come parametro ovunque.
In conclusione, potrebbero sicuramente esserci altri progetti migliori per un motore, ma ho trovato il motore proposto da questo link molto elegante, estremamente facile da mantenere e riutilizzabile. Personalmente consiglierei almeno di provarlo.