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 Update
e um Draw
método e ambos chamada os GameScreen
's Update
e Draw
métodos, que se passar por cada componente e chamada Update
e 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 BackgroundManager
todos os diferentes contextos específicos. Você só tem um ScrollingBackground
, ParallaxBackground
, StaticBackground
, etc., que todos derivam de uma Background
classe.
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, FrameRateDisplayer
como um utilitário de depuração, uma Sprite
classe 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 BackgroundManager
classe, mas uma Background
classe 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 Engine
dentro de todas as suas GameScreen
classes, para poder adicionar novas telas mesmo dentro de uma GameScreen
classe (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 Component
classe: ela deve conter a referência de seu pai GameScreen
, para ter acesso à Engine
classe e ao pai GameScreen
para adicionar novos componentes (por exemplo, você pode criar uma classe relacionada ao HUD chamada DrawableButton
que contém um
DrawableText
componente e um StaticBackground
componente).
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 Engine
classe (basta manter uma lista de se IService
permitir 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.