Eu quero desenvolver um enorme mapa do mundo; pelo menos 8000 × 6000 pixels de tamanho. Dividi-o em uma grade 10 × 10 de imagens PNG de 800 × 600 pixels. Para evitar carregar tudo na memória, as imagens devem ser carregadas e descarregadas, dependendo da posição do player na grade.
Por exemplo, aqui está o jogador na posição (3,3)
:
À medida que ele se move para a direita (4,3)
, as três imagens à esquerda são desalocadas enquanto as três imagens à direita são alocadas:
Provavelmente deve haver um limite dentro de cada célula da grade acionando o carregamento e o descarregamento. O carregamento provavelmente deve ocorrer em um thread separado.
Como faço para projetar esse sistema?
Respostas:
Existem alguns problemas a serem resolvidos aqui. A primeira é como carregar e descarregar blocos. O ContentManager, por padrão, não permite descarregar partes específicas do conteúdo. Uma implementação personalizada disso, no entanto, irá:
A segunda questão é como decidir quais blocos carregar e descarregar. O seguinte resolveria este problema:
A questão final é como decidir quando carregar e descarregar. Esta é provavelmente a parte mais fácil. Isso pode ser feito simplesmente no método Update () quando a posição da tela do jogador for determinada:
É claro que você também precisaria desenhar os blocos, mas, considerando o tileWidth, tileHeight e a matriz Tiles [], isso deve ser trivial.
fonte
O que você quer fazer é bastante comum. Para um bom tutorial sobre essa e outras técnicas comuns, confira esta série de mecanismos de blocos .
Se você não fez nada assim antes, recomendo assistir a série. No entanto, se você quiser, poderá obter o código dos últimos tutoriais. Se você fizer isso mais tarde, confira o método draw.
Em poucas palavras, você precisa encontrar seus pontos mínimo e máximo de X / Y ao redor do player. Depois de conseguir, basta percorrer cada uma delas e desenhar essa peça.
Como você pode ver, há muita coisa acontecendo. Você precisa de uma câmera para criar sua matriz, precisa converter sua localização atual de pixels em um índice de blocos, encontrar seus pontos mínimo / máximo (adiciono um pouco ao meu MAX para que ele se mova um pouco além da tela visível ) e, em seguida, você pode desenhá-lo.
Eu realmente sugiro assistir a série de tutoriais. Ele aborda o seu problema atual, como criar um editor de blocos, manter o jogador dentro dos limites, animação de sprites, interação com IA, etc.
Em uma nota lateral, o TiledLib incorporou isso. Você também pode estudar o código deles.
fonte
Eu tenho trabalhado em algo muito semelhante ao meu projeto atual. Esta é uma rápida descrição de como estou fazendo isso, com algumas anotações sobre como tornar as coisas um pouco mais fáceis para você.
Para mim, o primeiro problema foi dividir o mundo em pedaços menores que seriam apropriados para carregar e descarregar em tempo real. Como você está usando um mapa baseado em blocos, essa etapa se torna significativamente mais fácil. Em vez de considerar as posições de cada objeto 3D no nível, você já tem seu nível dividido em blocos. Isso permite que você simplesmente divida o mundo em pedaços de ladrilhos X por Y e carregue-os.
Você vai querer fazer isso automaticamente, e não manualmente. Como você usa o XNA, você tem a opção de usar o Pipeline de conteúdo com um exportador personalizado para o seu nível de conteúdo. A menos que você conheça alguma maneira de executar o processo de exportação sem recompilar, eu sinceramente recomendo. Embora o C # não seja tão lento para compilar quanto o C ++, você ainda não precisa carregar o Visual Studio e recompilar seu jogo toda vez que fizer uma pequena alteração no mapa.
Outra coisa importante aqui é garantir que você use uma boa convenção de nomenclatura para os arquivos que contêm os blocos do seu nível. Você deseja saber que deseja carregar ou descarregar o pedaço C e, em seguida, gerar o nome do arquivo que você precisa carregar para fazer isso em tempo de execução. Por fim, pense em pequenas coisas que possam ajudá-lo no caminho. É muito bom poder alterar o tamanho de um pedaço, reexportar e ver os efeitos disso no desempenho imediatamente.
Em tempo de execução, ainda é bastante direto. Você precisará de alguma maneira para carregar e descarregar de forma assíncrona pedaços, mas isso depende muito de como o seu jogo ou mecanismo funciona. Sua segunda imagem está exatamente correta - você precisa determinar quais blocos devem ser carregados ou descarregados e fazer as solicitações apropriadas para que isso aconteça, caso ainda não esteja. Dependendo de quantos pedaços você carregou ao mesmo tempo, você pode fazer isso sempre que o jogador cruzar um limite de um pedaço para o outro. Afinal, de qualquer maneira, você quer ter certeza de que está carregado o suficiente para que, mesmo no pior (razoável) tempo de carregamento, o pedaço ainda esteja carregado antes que o jogador possa vê-lo. Você provavelmente vai querer jogar muito com esse número até obter um bom equilíbrio entre desempenho e consumo de memória.
No que diz respeito à arquitetura real, você desejará abstrair o processo de realmente carregar e descarregar os dados da memória do processo de determinar o que deve ser carregado / descarregado. Para sua primeira iteração, eu nem me preocuparia com o desempenho do carregamento / descarregamento e apenas obteria a coisa mais simples que poderia funcionar, além de garantir que você esteja gerando as solicitações apropriadas nos momentos apropriados. Depois disso, você pode otimizar como você carrega para minimizar o lixo.
Encontrei muita complexidade adicional devido ao mecanismo que estava usando, mas isso é bastante específico da implementação. Se você tiver alguma dúvida sobre o que eu fiz, comente e farei o que puder para ajudar.
fonte