Tudo bem, formulado dessa maneira, tenho certeza que parece obscuro, mas farei o possível para descrever meu problema.
Primeiro, deixe-me explicar o que há de errado com meu código-fonte real.
Estou fazendo um jogo de plataformas, e aqui estão os componentes atuais do meu jogo: um Level , que contém sua própria grade de peças e também as folhas de peças e uma peça , que apenas mantém o nome da sua peça e o índice dentro do folha de azulejo. Tudo isso está em um projeto de jogo XNA separado, chamado GameLib.
Aqui está como meus níveis são formatados em um arquivo de texto:
x x . . . . .
. . . b g r .
. . . . . . .
X X X X X X X
Onde .
representa um bloco vazio, b
representa uma plataforma azul, X
representa um bloco com uma cor aleatória etc.
Em vez de fazer todo o trabalho de carregar um nível na classe Level , decidi aproveitar a extensão do pipeline de conteúdo e criar um LevelContentPipelineExtension.
Assim que comecei, percebi rapidamente que não queria codificar mais de 20 linhas do tipo:
if (symbol == 'b')
return new Tile(/*...*/);
Portanto, na esperança de pelo menos centralizar toda a criação de conteúdo em uma classe, criei uma classe estática, chamada LevelContentCreation , que contém as informações sobre qual símbolo cria o que e todo esse tipo de coisa. Ele também contém uma lista de todos os caminhos de ativos das folhas de mosaico, para carregá-los posteriormente. Esta classe está dentro do meu projeto de biblioteca de jogos GameLib.
O problema é que estou usando essa classe estática LevelContentCreation na minha classe Level (para carregar as folhas de bloco reais) e na extensão do pipeline de conteúdo (para saber qual símbolo representa qual bloco) ...
E aqui está como minha classe LevelContentCreation se parece:
public static class LevelContentCreation
{
private static Dictionary<char, TileCreationInfo> AvailableTiles =
CreateAvailableTiles();
private static List<string> AvailableTileSheets { get; set; }
/* ... rest of the class */
}
Agora, como a classe LevelContentCreation faz parte da biblioteca de jogos, a extensão do pipeline de conteúdo tenta usá-lo, mas a chamada para CreateAvailableTiles () nunca acontece e não consigo carregar um objeto Level do pipeline de conteúdo.
Eu sei que isso ocorre porque o pipeline de conteúdo é executado antes da compilação real ou algo parecido, mas como posso corrigir o problema?
Não consigo mover o LevelContentCreation classe para a extensão do pipeline, porque a classe Level não seria capaz de usá-lo ... Estou muito perdida e não sei o que fazer ... Eu sei disso são decisões de design muito ruins, e eu gostaria que alguém pudesse me apontar na direção certa.
Obrigado pelo seu precioso tempo.
Se alguma coisa não estiver clara o suficiente ou se devo fornecer mais informações / código, deixe um comentário abaixo.
Um pouco mais de informação sobre meus projetos:
- Jogo - projeto de jogo do XNA Windows. Contém referências a: Engine, GameLib e GameContent
- GameLib - projeto de biblioteca de jogos XNA. Contém referências a: Mecanismo
- GameContent - projeto de conteúdo XNA. Contém referências a: LevelContentPipelineExtension
- Engine - projeto da biblioteca de jogos XNA. Sem referências.
- LevelContentPipelineExtension - extensão de pipeline de conteúdo XNA. Contém referências a: Engine e GameLib
Não sei quase nada sobre o XNA 4.0 e estou um pouco perdido sobre como o conteúdo funciona agora. Se precisar de mais informações, me diga.
Respostas:
Nos casos em que você está usando singletons, classes estáticas ou variáveis globais, 99% das vezes o que você realmente deveria estar usando é um serviço de jogo . Os serviços de jogos são usados quando você deseja que uma instância de uma classe esteja disponível para todas as outras classes, mas o forte acoplamento das outras opções oferece um sabor engraçado. Os serviços também não têm os problemas de instanciação que você viu, são mais reutilizáveis e podem ser ridicularizados (se você se preocupa com o teste de unidade automatizado) .
Para registrar um serviço, você precisa dar à sua classe sua própria interface. Então é só ligar
Game.Services.AddService()
. Para usar posteriormente esse serviço em outra classe, chameGame.Services.GetService()
.No seu caso, sua classe seria mais ou menos assim:
Em algum momento no início do programa, você precisará registrar seu serviço
Game.Services
. Eu prefiro fazer isso no início deLoadContent()
, mas algumas pessoas preferem registrar cada serviço no construtor dessa classe.Agora, sempre que você quiser acessar sua
LevelContentCreation
classe em qualquer outra classe, basta fazer o seguinte:Como uma observação lateral, esse paradigma é conhecido como Inversão de Controle (IoC) e também é amplamente usado fora do desenvolvimento do XNA. A estrutura mais popular para IoC no .Net é o Ninject , que possui uma sintaxe melhor do que os métodos Game.Services:
Ele também suporta injeção de dependência , uma forma de IoC que é um pouco mais complexa, mas muito mais agradável de se trabalhar.
[Edit] É claro, você também pode obter essa boa sintaxe com o XNA:
fonte
Na verdade, encontrei uma maneira de corrigir o problema: removi a classe estática e a tornei uma classe normal. Dessa forma, tenho certeza de que as instruções corretas são executadas no momento certo.
Eu gostaria de não ter desperdiçado seu tempo assim, mas realmente tive a ideia de fazê-lo lendo os comentários / respostas.
Obrigado mesmo assim.
fonte
if
/switch
declarações que simplesmente retornam tipos diferentes, provavelmente deseja que esses valores façam parte da classe. No seu caso, eu criaria umaTileType
classe que contém informações (textura, salvar arquivo-letra, etc.) sobre cada tipo de bloco. Em seguida, para obter umaTileType
carta, basta pesquisar na sua lista deTileTypes
, ou se você estiver preocupado com o desempenho, armazene uma estáticaDictionary<char, TileType>
naTileType
classe (você pode preenchê-la automaticamente noTileType
construtor).Tile
(classe que representa um único bloco exibido na tela) referencia um únicoTileType
. Se um número suficiente de seus blocos tiver um comportamento exclusivo que exija código especial, convém usar uma hierarquia de classes.Dê uma olhada no seguinte: http://msdn.microsoft.com/en-us/library/bb447745.aspx
Para o layout de nível, basta colocar uma função dentro da minha classe Level chamada "LoadFromFile (string name)". Porque se você quiser adicionar suporte para mapas personalizados no seu jogo mais tarde, precisará salvar e carregar os níveis do seu próprio formato de arquivo.
Você também pode criar um importador de conteúdo, para carregar dos ativos incluídos e também dos arquivos fornecidos pelo usuário. Consulte esta página para obter mais informações sobre como criar um importador.
http://msdn.microsoft.com/en-us/library/bb447743.aspx
fonte