Tenho pesquisado na Internet para encontrar uma maneira eficiente de criar um mapa de bloco procedural sem criar um GameObject por bloco. Todos os tutoriais de TileMap que encontrei estão criando blocos criando centenas de GameObjects. Portanto, a hierarquia no Unity está se expandindo inesperadamente.
Tenho certeza de que essa não é a maneira “certa” de fazer isso. Especialmente depois de ver as novas ferramentas Unity 2D que oferecem suporte a mapas de blocos. O Unity fez isso, você pode criar blocos em “um” objeto de jogo, não para cada bloco.
Então, como faço isso da maneira certa e eficiente?
Comentários
- Você ‘ cruzou a postagem para dois sites SE. Escolha um.
- O que ‘ é sua preocupação específica com a criação de um grande número de GameObjects? Se ‘ é apenas desordem de hierarquia, existem maneiras fáceis de corrigir isso. Unity ‘ O lote deve combinar blocos semelhantes em um único lote de qualquer maneira, então ‘ é improvável que haja uma grande penalidade de empate por fazer isso desta forma. Minimizando blocos fora da tela e o tempo gasto nas funções de atualização dos blocos também são problemas solucionáveis. Você fez o perfil do seu jogo e identificou uma especificação c gargalo que você ‘ está tentando resolver?
- @DMGregory Bem, se pensarmos em 100 * 100 mapa na tela (se assumirmos que diminuímos o zoom para ver todo mapa), ele fará 10.000 objetos de jogo na cena. Também significa 10.000 componentes de transformação desnecessários. Eu não ‘ nem sei se a unidade pode suportar 10.000 objetos na janela de hierarquia. Eu sei que ele congela após algumas centenas.
Resposta
Aqui está o que estou ciente:
Opção 1. GameObject por bloco. Não é completamente horrível em certos casos. Dependendo de suas necessidades, pode funcionar … bem o suficiente.
Opção 2. Um único quadrante ou plano referenciando uma textura que você cria em tempo de execução. Basicamente, use a textura do atlas de blocos para “pintar” seu mapa como uma nova textura. Dependendo do tamanho do mapa, é claro, você pode querer ter vários quadrantes / planos, cada um representando partes do mapa.
Opção 3. Crie sua própria malha. Este seria mais do que provavelmente o método que você mais gostará depois de implementado. Isso “dará a você toneladas de flexibilidade e provavelmente o melhor desempenho. Você essencialmente criaria um quad por bloco e definiria cada vértice UV para mapear para os blocos em seu atlas de blocos.
Para a opção 2, I” d sugiro assistir a esta série de vídeos por quill18creates: Série de tutoriais 3D TileMap por quill18creates
Para a opção 3, este é o meu código, com ajustes, portanto, pode não ser perfeito:
//For this, your GameObject this script is attached to would have a //Transform Component, a Mesh Filter Component, and a Mesh Renderer //component. You will also need to assign your texture atlas / material //to it. void Start() { meshFilter = GetComponent<MeshFilter>(); BuildMesh(); } public void BuildMesh() { int numTiles = mapSizeX * mapSizeY; int numTriangles = numTiles * 6; int numVerts = numTiles * 4; Vector3[] vertices = new Vector3[numVerts]; UVArray = new Vector2[numVerts]; int x, y, iVertCount = 0; for (x = 0; x < mapSizeX; x++) { for (y = 0; y < mapSizeY; y++) { vertices[iVertCount + 0] = new Vector3(x, y, 0); vertices[iVertCount + 1] = new Vector3(x + 1, y, 0); vertices[iVertCount + 2] = new Vector3(x + 1, y + 1, 0); vertices[iVertCount + 3] = new Vector3(x, y + 1, 0); iVertCount += 4; } } int[] triangles = new int[numTriangles]; int iIndexCount = 0; iVertCount = 0; for (int i = 0; i < numTiles; i++) { triangles[iIndexCount + 0] += (iVertCount + 0); triangles[iIndexCount + 1] += (iVertCount + 1); triangles[iIndexCount + 2] += (iVertCount + 2); triangles[iIndexCount + 3] += (iVertCount + 0); triangles[iIndexCount + 4] += (iVertCount + 2); triangles[iIndexCount + 5] += (iVertCount + 3); iVertCount += 4; iIndexCount += 6; } mesh = new Mesh(); //mesh.MarkDynamic(); if you intend to change the vertices a lot, this will help. mesh.vertices = vertices; mesh.triangles = triangles; meshFilter.mesh = mesh; UpdateMesh(); //I put this in a separate method for my own purposes. } //Note, the example UV entries I have are assuming a tile atlas //with 16 total tiles in a 4x4 grid. public void UpdateMesh() { int iVertCount = 0; for (int x = 0; x < mapSizeX; x++) { for (int y = 0; y < mapSizeY; y++) { UVArray[iVertCount + 0] = new Vector2(0, 0); //Top left of tile in atlas UVArray[iVertCount + 1] = new Vector2(.25f, 0); //Top right of tile in atlas UVArray[iVertCount + 2] = new Vector2(.25f, .25f); //Bottom right of tile in atlas UVArray[iVertCount + 3] = new Vector2(0, .25f); //Bottom left of tile in atlas iVertCount += 4; } } meshFilter.mesh.uv = UVArray; }
Comentários
- Suas respostas me ajudaram no dias. Agora, estou examinando minhas perguntas antigas e ‘ percebi que ‘ nunca verifiquei se essa resposta foi aceita. Desculpe pela aprovação tardia de uma eternidade ^^ Obrigado pela resposta.
Resposta
Como você (eu acho ) aludido, o roteiro da Unity tem planos para um editor de mapas de blocos. Estou ansioso por isso, porque agora é um pouco confuso como proceder.
Enquanto isso, a melhor abordagem é “Estou vendo é fazer seu mapa no Tiled e usar o X-UniTMX para importá-lo para o Unity. Obviamente, isso não é geração procedural; eu imagino que você usaria a mesma técnica que o X-UniTMX está usando para criar a malha.
Resposta
Você poderia simplesmente ter os tiles criados mais profundamente na hierarquia e fechar essa pasta e não se incomodar. O que você também pode fazer é ocultar seus objetos de jogo da hierarquia `myTile.hideFlags = HideFlags. HideInHierarchy “não tem certeza sobre quanto desempenho seria obtido.
Mostrar texturas 100×100 na tela nunca é uma boa ideia desenhar texturas é mais pesado do que desenhar polígonos. Se você precisar diminuir tanto o zoom, será melhor usar texturas maiores. O mesmo vale para o zoom, você não deve desenhar as texturas que não precisam ser desenhadas.
O que eu normalmente faço (eu não sou um cara do Unity) é criar uma classe para um mapa e usar um array bidimensional para conter todos os seus tiles. Este array pode ser simplesmente de ints ou uma classe Tile com um par de ints que se referem às suas texturas, tipo de tile, objetos, etc. Então, seria desenhado da seguinte maneira:
for (int y = 0; y < mapHeight; y++) { for(int x = 0; x < mapHeight; x++) { Graphics.DrawTexture(new Rect(x * tileWidth, y * tileHeight, tileWidth, tileHeigt), tileTexture); } }
O método de desenho que uso parece ser para desenhar uma GUI, mas pode ser perfeitamente adequado para a tarefa. Caso contrário, você terá que cavar no gerenciador de sprite e encontrar uma maneira que funciona com este método.
Você pode usar um dicionário para referência de textura como int 1
em sua classe de bloco se refere a alguma textura e int 2
refere-se a outro.Na linha que você está desenhando sua textura, você usaria seu dicionário para fornecer o objeto de textura correto. Dessa forma, ele não deve criar um GameObject e, portanto, não deve criar toda a sobrecarga desnecessária.
Você pode fazer o mesmo para praticamente tudo que não precisa do nível de controle de um GameObject. Lembre-se, porém, de que desta forma ele desenhará todos os ladrilhos do seu mapa, provavelmente não selecionará automaticamente os objetos como eu acho que a unidade faz com os objetos do jogo. Mas apenas desenhar o que precisa estar na tela é muito fácil. Você sabe o tamanho da tela / janela de exibição, a posição da câmera e o tamanho do ladrilho. Um pouco de matemática simples deve desenhar exatamente o que é necessário.
Ainda assim, a unidade é um mecanismo 3D. Ele apenas suporta 2D de uma forma 3D. Mas você pode basicamente fazer a mesma coisa para quadrantes / malhas com texturas e uma câmera ortográfica. Desenhar as malhas necessárias já é muito barato.
Resposta
Como alguém que trabalha em um projeto baseado em voxel / bloco , Não posso deixar de pensar apenas em usar a mesma abordagem, apenas em 2D. Você pode construir uma malha em forma de grade proceduralmente e atribuir as coordenadas corretas de visuais de blocos em seu atlas de textura para o canal UV. Em 3D, você tem que fazer muito mais trabalho do que isso para ter alto desempenho, mas em 2D é muito provável que seja realmente o suficiente.
Resposta
Você sempre pode usar LeanPool . É um ativo gratuito na loja de ativos. Ele faz pooling de objetos para você. Em seguida, você pode fazer um sistema de seleção simples em torno da visualização das câmeras que gera / desova objetos de jogo de blocos conforme eles entram / saem da visualização das câmeras. Não tenho certeza de quão grande será o seu mapa de blocos, mas o Unity pode lidar com vários objetos de jogo. LeanPool tem cenas de benchmark no Unity onde você pode gerar / desovar milhares de objetos com componentes de colisão de caixa e eu acho que possivelmente um componente de renderização em cada um e faz isso muito rapidamente.
https://gamedevacademy.org/how-to-script-a-2d-tile-map-in-unity3d/
Aqui está um link que mostrará a você um exemplo de uso de LeanPool com um mapa de blocos.