Como você gerencia seus recursos de jogo no XNA?

7

No passado, eu usei em Content.Load<type>("filename");todo o lugar. Isso rapidamente se torna um pesadelo para gerenciar e, pior ainda, você começa a ter várias cópias do mesmo ativo carregadas em vários lugares diferentes.

Depois, passei a usar uma classe Resources, que basicamente se parecia com o seguinte:

public class Resources
{
    public static Texture2D particle01;
    ...
    public static Texture2D particle93;

    public static Effect shader01;
    ...
    public static Effect shader32;

    public static Load(ContentManager content, GraphicsDevice device)
    { //load all the resources }

    public static Unload()
    { //unload all the resources }
}

Então eu poderia simplesmente usar Resources.particle01para obter uma referência ao recurso de qualquer lugar dentro do mesmo espaço para nome.

Essa foi uma ótima abordagem, pois eliminou as duplicatas que eu tinha no passado. Além disso, todo o carregamento foi feito em uma única classe, facilitando o controle dos recursos. E, finalmente, eu poderia simplesmente clicar com o botão direito, por exemplo, particle93e clicar em encontrar todas as referências para encontrar todos os lugares que usavam essa textura.

No entanto, existem problemas com essa abordagem e eu gostaria de saber se existe uma solução melhor por aí.

radenon
fonte

Respostas:

8

Bem, para iniciantes, o gerenciador de conteúdo do XNA não carrega o mesmo ativo duas vezes, apenas retornará uma referência se algo já estiver carregado.

Quanto à sua abordagem de recursos, não sei se esse é realmente o caminho a seguir, já que você basicamente codifica seus recursos de conteúdo no seu jogo.

Uma possível solução para o seu problema seria o padrão de fábrica. Digamos que você queira carregar um nível armazenado como XML. Você carrega o arquivo XML e carrega o nível executando LevelFactory.Construct (xml); Esta fábrica inspeciona o arquivo XML e carrega todos os ativos associados a esse nível e os coloca no mundo. Sub-partes do mundo como NPCs podem ser construídas pela fábrica de níveis, chamando a fábrica de NPC e passando parte do arquivo XML para que a fábrica de NPC saiba carregar quais texturas e modelos.

Usando essa abordagem, você obtém uma 'série em cascata' de fábricas, todas orientadas por dados, para que você possa ter uma separação clara entre o conteúdo (o arquivo XML e os arquivos referenciados pelo arquivo XML) e o código (as fábricas). Enquanto mantém o conteúdo carregando o código longe do outro código. Agora você não tem todo Player = new Player (textureA, textureB, textureC); mais, você pode simplesmente pedir à fábrica um novo jogador e ele descobrirá o resto.

Dica: você sempre pode ter alguns métodos para objetos padrão ou um fallback quando nada for especificado no XML.

Espero que isto ajude!

Roy T.
fonte
3

Eu usei o FlatRedBall, que tem um conceito incrível de telas. Em vez de se preocupar em carregar / descarregar texturas, você escreve um código como:

Sprite s = this.addSprite("spaceship");

E ele lidará com o ciclo de vida do conteúdo para você. Eu também uso essa abordagem em minha própria estrutura, a Radiant Wrench. Eu acho que isso mantém a gerência no mínimo e fica fora do seu caminho.

O código para gerenciar sprites não é tão trivial (você precisa de uma classe de sprite e uma classe de tela, para iniciantes), então sugiro que experimente o FRB ou o RW . Você sempre se beneficiará ao aprender novas maneiras de fazer as coisas (às vezes, maneiras melhores).

ashes999
fonte
2

Isso pode parecer desfavorável para alguns, mas eu tendem a manter meus recursos locais no GameState que precisa deles, e cada GameState possui um tipo de ResourcePool. Essa é uma ótima maneira de manter ativos de nível separados, pois eu realmente não preciso de planos de fundo de menu. Sua classe de Recursos seria melhor servida como uma estrutura e o GameState será responsável por Carregar e Descarregar.

Parte do gerenciamento de recursos no XNA é parcialmente determinado por como você importa seu conteúdo em primeiro lugar. Muitas pessoas vinculam texturas e efeitos a seus modelos na fase de processamento de conteúdo da construção, deixando-as apenas para gerenciar malhas e o restante já é mencionado nela.

Você parece adotar a abordagem mais clássica de "misturar e combinar" para obter mais flexibilidade, portanto, precisa de uma abordagem que marque o trabalho subjacente e corte o código que você precisa escrever a longo prazo. Eu não usei o FlatRedBall, mas pelo que sei da breve descrição escrita aqui, parece o padrão Lazy Loading . É um conceito que vale a pena examinar se você deseja facilitar sua vida com o gerenciamento de muitos recursos.

ChrisC
fonte
Pequeno comentário, uma estrutura que tem referências a tipos não de valor não tem muita utilidade.
Roy T.
1

Eu uso uma classe estática pública chamada Assets. Ele contém dicionários de cada tipo de ativo, modelo, efeito, aspas de sprite, etc., possui uma função de carregamento, na qual procura na pasta de conteúdo pastas como "Texturas", "Modelos", etc., e carrega todos os ativos. Então, quando eu quero chamar um Asset, apenas uso algo como Assets.Textures ["SpriteSheetX"];

Não sei se isso é uma prática ruim, mas é muito fácil. Na maioria das vezes, passo apenas as strings do nome do arquivo e, no fundo, ele carregará o ativo do Assets.

Theodore Enderby
fonte