Estou fazendo um pequeno rastreador de masmorra no espaço e gostaria de ouvir alguns conselhos sobre como melhorar o back-end do motor. Basicamente, atualmente tudo é baseado em um upload de gerentes:
- BackgroundManager: possui um
AddBackground(image, parallax)
método para criar efeitos interessantes de fundo. - ConfigManager: lê / cria o arquivo de configuração e também retém os dados lidos nesse arquivo de configuração.
- DrawManager: possui um
Draw(sprite)
método para desenhar coisas na tela, coisas assimSetView(view)
,GetView()
etc. - EntityManager: mantém todas as entidades ativas e possui métodos para adicionar, remover e localizar entidades.
- DungeonManager (na verdade chamado de GridManager, mas isso é para simplificar): tem métodos como
GenerateDungeon()
,PlaceEnemies()
,PlaceFinish()
etc.
Agora nem estou na metade do caminho listando todos os meus gerentes, então acho que isso precisa mudar. Meu jogo também é baseado em Telas, o que o torna mais irritante porque não preciso da metade das coisas que meus gerentes estão gerenciando, por exemplo, no menu principal (não preciso de física / entidades / masmorras no meu menu principal). !)
Agora, pensei em tornar os gerentes não estáticos e em dar ao meu ScreenMainGame uma instância de todos os gerentes específicos de jogos. Mas isso torna a chamada / obtenção de algo relacionado aos gerentes uma grande bagunça ... por exemplo, se eu quisesse desenhar minha masmorra de qualquer lugar que não ScreenMainGame.Draw()
estivesse, eu teria que fazer isso ...
((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()
Isso é realmente feio.
Então, colegas desenvolvedores de jogos, algum de vocês tem uma idéia de como resolver essa bagunça? Eu seria apreciado!
fonte
Respostas:
E quanto a um mecanismo baseado em componente ?
Você teria uma classe principal denominada
Engine
, que manteria uma lista deGameScreens
, e eles próprios manteriam uma lista deComponents
.O motor tem um
Update
e umDraw
método e ambos chamada osGameScreen
'sUpdate
eDraw
métodos, que se passar por cada componente e chamadaUpdate
eDraw
.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 umScrollingBackground
,ParallaxBackground
,StaticBackground
, etc., que todos derivam de umaBackground
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, umaSprite
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 umaBackground
classe que se autodirecionaria.Quando o jogo começa, tudo o que você precisa fazer é basicamente isso:
E é isso para o seu código de início do jogo.
Em seguida, para a tela do menu principal:
Você entende a ideia geral.
Você também manteria a referência
Engine
dentro de todas as suasGameScreen
classes, para poder adicionar novas telas mesmo dentro de umaGameScreen
classe (por exemplo, quando o usuário clicar no botão StartGame enquanto estiver dentro do seuMainMenuScreen
, você poderá fazer a transição para oGameplayScreen
).O mesmo vale para a
Component
classe: ela deve conter a referência de seu paiGameScreen
, para ter acesso àEngine
classe e ao paiGameScreen
para adicionar novos componentes (por exemplo, você pode criar uma classe relacionada ao HUD chamadaDrawableButton
que contém umDrawableText
componente e umStaticBackground
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 seIService
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.
fonte
GameComponent
serviços e serviços. Não há necessidade de umaEngine
aula separada .O que você deseja fazer é separar seu código em componentes e serviços. O XNA já possui suporte interno para eles.
Veja este artigo no
GameComponents
e serviços. Então veja esta resposta sobre o uso de serviços no XNA e essa resposta mais geral sobre serviços em qualquer idioma.fonte
Só porque eles são estáticos ou globais não significa que eles sempre devem ser carregados / inicializados. Use um padrão Singleton e permita que os gerentes sejam liberáveis e carregados novamente sob demanda.
fonte