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 Update
e un Draw
metodo ed entrambi chiamano GameScreen
"s" Update
e Draw
metodi, che a loro volta passano attraverso ogni componente e chiamano Update
e 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 BackgroundManager
tutti i diversi sfondi specifici. Devi solo una ScrollingBackground
, ParallaxBackground
, StaticBackground
, ecc, che derivano tutte da una Background
classe.
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 FrameRateDisplayer
come utilità di debug, una Sprite
classe come uno sprite di base con una trama e metodi di estensione per i vettori e generazione di numeri casuali).
Non avresti più una BackgroundManager
classe, ma una Background
classe 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 Engine
all'interno di tutte le tue GameScreen
classi, per poter aggiungere nuove schermate anche all'interno di una GameScreen
classe (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 Component
classe: dovrebbe contenere il riferimento del suo genitore GameScreen
, per avere sia l'accesso alla Engine
classe sia il suo genitore GameScreen
per aggiungere nuovi componenti (ad esempio puoi creare una classe relativa a HUD chiamata DrawableButton
che contiene un
DrawableText
componente e un StaticBackground
componente).
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 Engine
classe (semplicemente tieni un elenco di se IService
lasci che altre classi aggiungano servizi da soli ). ad es. manterrei un Camera2D
componente 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.