E quanto a um mecanismo baseado em componente ?
Você teria uma classe principal denominada Engine, que manteria uma lista de GameScreens, e eles próprios manteriam uma lista de Components.
O motor tem um Updatee um Drawmétodo e ambos chamada os GameScreen's Updatee Drawmétodos, que se passar por cada componente e chamada Updatee Draw.
Apresentado assim, concordo que parece um design pobre e repetitivo. Mas acredite, meu código ficou muito mais limpo usando uma abordagem baseada em componentes do que com todas as minhas classes antigas de gerenciador .
É muito mais simples manter esse código também, já que você está passando por uma grande hierarquia de classes e não precisa pesquisar BackgroundManagertodos os diferentes contextos específicos. Você só tem um ScrollingBackground, ParallaxBackground, StaticBackground, etc., que todos derivam de uma Backgroundclasse.
Você criará um mecanismo bastante sólido que poderá ser reutilizado em todos os seus projetos com muitos componentes e métodos auxiliares usados com frequência (por exemplo, FrameRateDisplayercomo um utilitário de depuração, uma Spriteclasse como um sprite básico com métodos de textura e extensão para vetores e geração de números aleatórios).
Você não teria mais uma BackgroundManagerclasse, mas uma Backgroundclasse que se autodirecionaria.
Quando o jogo começa, tudo o que você precisa fazer é basicamente isso:
// 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 é isso para o seu código de início do jogo.
Em seguida, para a tela do 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);
}
}
}
Você entende a ideia geral.
Você também manteria a referência Enginedentro de todas as suas GameScreenclasses, para poder adicionar novas telas mesmo dentro de uma GameScreenclasse (por exemplo, quando o usuário clicar no botão StartGame enquanto estiver dentro do seu MainMenuScreen, você poderá fazer a transição para oGameplayScreen ).
O mesmo vale para a Componentclasse: ela deve conter a referência de seu pai GameScreen, para ter acesso à Engineclasse e ao pai GameScreenpara adicionar novos componentes (por exemplo, você pode criar uma classe relacionada ao HUD chamada DrawableButtonque contém um
DrawableTextcomponente e um StaticBackgroundcomponente).
Você pode até aplicar outros padrões de design depois disso, como o "padrão de design de serviço" (não tenho certeza sobre o nome exato), onde você pode manter diferentes serviços úteis em sua Engineclasse (basta manter uma lista de se IServicepermitir que outras classes adicionem serviços ) por exemplo, eu manteria umCamera2D componente em todo o meu projeto como um serviço para aplicar sua transformação ao desenhar outros componentes. Isso evita ter que passar como parâmetro em qualquer lugar.
Em conclusão, certamente pode haver outros projetos melhores para um mecanismo, mas achei o mecanismo proposto por esse link muito elegante, extremamente fácil de manter e reutilizar. Pessoalmente, eu recomendaria pelo menos tentar.