Voltar para o Blog
Quest Log

GridMap na Godot: montar cenário 3D com blocos

Nível de dungeon 3D montado com blocos modulares em grade dentro do editor de uma game engine, vista isométrica

Aprenda a usar o GridMap da Godot 4 com uma MeshLibrary para montar cenário 3D com blocos: criar a biblioteca, pintar no editor, ativar colisão e editar células por código.

Ferramenta:Godot

Modelar um cenário 3D peça por peça é lento, e nem sempre você precisa disso para testar um nível. Se o seu jogo tem corredores, salas e dungeons feitos de pedaços repetidos, o GridMap na Godot 4 resolve: você desenha uma vez cada bloco, junta tudo numa MeshLibrary e pinta o mapa inteiro encaixando esses blocos numa grade 3D, direto no editor. Neste guia você vai montar a biblioteca de blocos, pintar um cenário, ativar a colisão e ainda editar as células por código para gerar ou destruir partes do mapa em tempo de execução.

O que é o GridMap e quando usar

O GridMap é um nó da Godot que funciona como um TileMap em três dimensões. Em vez de tiles planos, ele encaixa malhas 3D em uma grade com células que têm largura, profundidade e altura. Cada célula guarda o ID de um bloco da sua MeshLibrary, e a Godot cuida de posicionar, repetir e otimizar o desenho de tudo.

Ele brilha em cenários modulares: dungeons de blocos, labirintos, construções em grade, mundos estilo voxel grosso, arenas feitas de peças padronizadas. Sempre que o nível puder ser descrito como "encaixe desses pedaços nesta grade", o GridMap monta em minutos o que levaria horas de posicionamento manual de MeshInstance3D.

Quando ele não é a melhor escolha: cenários orgânicos, com formas livres, curvas e objetos únicos espalhados sem padrão. Aí o caminho é modelar no Blender e importar. Se a sua dúvida é mais básica, como importar um modelo 3D do Blender para a Godot, resolva isso primeiro e volte: os blocos da sua MeshLibrary podem muito bem ser malhas vindas do Blender.

Passo 1: criar os blocos como cenas

O GridMap não cria geometria. Ele só sabe repetir blocos que você já construiu. Então o primeiro passo é montar cada peça como uma cena separada.

Para um bloco simples de piso, crie uma cena com um MeshInstance3D na raiz e atribua a ele uma BoxMesh de 2 x 0.2 x 2, por exemplo. Para uma parede, outra cena com uma caixa mais alta e fina. O importante é manter todos os blocos no mesmo tamanho de célula, ou múltiplos dele, para que encaixem sem sobrar vão nem sobrepor.

Uma dica de escala: decida logo o tamanho da sua célula (digamos 2 unidades) e modele cada bloco respeitando esse grid. Se quiser prototipar as formas antes de caprichar na arte, o fluxo de blockout com nós CSG para prototipar cenário 3D ajuda a definir dimensões e só depois você converte em blocos definitivos.

Passo 2: adicionar colisão em cada bloco

Se você quer que o personagem ande sobre o piso e esbarre nas paredes, cada bloco precisa carregar a própria colisão. O GridMap recria essa colisão em toda célula pintada, então basta configurar uma vez por bloco.

Na cena do bloco, adicione um StaticBody3D como filho e, dentro dele, um CollisionShape3D com uma BoxShape3D do mesmo tamanho da malha. A estrutura da cena fica assim:

  • MeshInstance3D (raiz do bloco)
    • StaticBody3D
      • CollisionShape3D

Quando a MeshLibrary for gerada a partir dessa cena, a Godot guarda tanto a malha quanto a forma de colisão no item. Nenhum ajuste extra depois: toda célula que usar esse bloco já vem com chão sólido.

Passo 3: gerar a MeshLibrary

Com os blocos prontos, junte todos numa única cena para converter de uma vez. Crie uma cena nova com um Node3D na raiz e coloque cada bloco como filho, um ao lado do outro para não se sobreporem na visualização. O nome de cada nó filho vira o nome do item na biblioteca, então nomeie com clareza: piso, parede, pilar, escada.

Agora converta. No menu superior do editor, abra Scene, depois Convert To, e escolha MeshLibrary. Salve como um arquivo .tres, por exemplo blocos.tres. A Godot cria um item por nó filho, preservando malha e colisão de cada um.

Toda vez que você mudar um bloco, repita a conversão para atualizar o .tres. O GridMap passa a refletir a mudança em todas as células que usam aquele bloco.

Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Passo 4: pintar o cenário no editor

Adicione um nó GridMap à sua cena principal. No Inspector, no campo Mesh Library, arraste o seu blocos.tres. Confira também o Cell Size para bater com a escala dos seus blocos (se a célula é 2 unidades, use 2 nos eixos).

Assim que a biblioteca é atribuída, uma paleta de blocos aparece no painel lateral direito do editor. Selecione um bloco na paleta e clique na viewport para pintar células. Os atalhos essenciais:

  • Clique esquerdo: coloca o bloco selecionado na célula.
  • Clique direito: apaga a célula.
  • Tecla S: gira o bloco no eixo Y antes de colocar.
  • Roda do mouse com a barra de ferramentas do GridMap: sobe ou desce o nível (floor) de pintura, para empilhar andares.

O plano de pintura segue um "floor" ativo. Para construir paredes sobre o piso, suba um nível e pinte os blocos de parede ali. Com poucos cliques você fecha uma sala inteira.

Passo 5: editar células por código

A parte poderosa do GridMap é que ele é totalmente scriptável. Dungeons procedurais, blocos destrutíveis, portas que somem: tudo passa por dois métodos, set_cell_item para escrever e get_cell_item para ler. As coordenadas são sempre um Vector3i em espaço de grade, não em unidades do mundo.

extends GridMap

# IDs dos itens na MeshLibrary (confira na paleta do editor)
const PISO: int = 0
const PAREDE: int = 1

func _ready() -> void:
    gerar_sala(Vector3i(0, 0, 0), 6, 4)

func gerar_sala(origem: Vector3i, largura: int, profundidade: int) -> void:
    for x in range(largura):
        for z in range(profundidade):
            var pos: Vector3i = origem + Vector3i(x, 0, z)
            set_cell_item(pos, PISO)
            # levanta parede nas bordas da sala
            var na_borda: bool = x == 0 or z == 0 \
                or x == largura - 1 or z == profundidade - 1
            if na_borda:
                set_cell_item(pos + Vector3i(0, 1, 0), PAREDE)

Para ler o que existe numa célula, use get_cell_item. Ele devolve o ID do bloco ou a constante GridMap.INVALID_CELL_ITEM quando a célula está vazia:

func tem_bloco(pos: Vector3i) -> bool:
    return get_cell_item(pos) != GridMap.INVALID_CELL_ITEM

func destruir_bloco(pos: Vector3i) -> void:
    if tem_bloco(pos):
        set_cell_item(pos, GridMap.INVALID_CELL_ITEM)

Passar INVALID_CELL_ITEM para set_cell_item limpa a célula, que é como você "destrói" um bloco em runtime. Para converter uma posição do mundo (por exemplo, onde o jogador clicou) em coordenada de grade, use local_to_map, e map_to_local para o caminho inverso:

func bloco_sob_o_mundo(ponto_mundo: Vector3) -> int:
    var celula: Vector3i = local_to_map(ponto_mundo)
    return get_cell_item(celula)

Com esses quatro métodos você cobre a maioria dos casos: gerar o mapa, consultar, limpar e traduzir coordenadas. A partir daí, um algoritmo de geração procedural de dungeon é só uma função que decide quais Vector3i recebem quais IDs.

Otimização e limites

O GridMap já agrupa a renderização dos blocos iguais, o que o torna leve mesmo com centenas de células. Ainda assim, vale ter em mente alguns pontos. Blocos com muitos polígonos multiplicam o custo, então mantenha as malhas enxutas. A colisão também é recriada por célula, portanto formas de colisão simples (caixas) rendem bem mais que malhas de colisão complexas.

Para cenários enormes, considere dividir o mundo em vários GridMaps por região e carregar só o que está perto do jogador. E lembre que o GridMap é ótimo para a estrutura, não para o acabamento: ilumine, adicione props soltos e detalhes por cima para que o nível não pareça feito de caixas repetidas.

Vale também cuidar da organização dos IDs. Como set_cell_item trabalha com números, é fácil se perder quando a MeshLibrary cresce. Mantenha as constantes dos blocos num único lugar do script, com nomes claros, e confira o ID de cada item na paleta do editor antes de usá-lo no código. Se você reordenar os blocos na cena de origem e reconverter a biblioteca, os IDs podem mudar, então centralizar essas constantes evita caça a bugs silenciosos em mapas gerados por código.

Por fim, teste a navegação cedo. Pinte um trecho pequeno, suba o personagem e ande por ele antes de encher o mapa inteiro. É muito mais barato descobrir que a célula ficou estreita ou que a parede não tem colisão numa sala do que no nível todo já montado.

Próximos passos

Com o GridMap você sai do zero a um nível 3D navegável em uma tarde, sem modelar cada parede. O fluxo completo é: desenhar os blocos, dar colisão, gerar a MeshLibrary, pintar e, quando precisar, scriptar as células. Se este é o seu primeiro contato com 3D na engine, vale montar antes a base com o guia de primeiro jogo 3D na Godot, que cobre cena, câmera e movimento de personagem.

E se você ainda está decidindo em qual engine investir seu tempo para criar jogos 3D, a comparação completa entre Godot e Unity ajuda a pesar o fluxo de level design, a curva de aprendizado e o licenciamento antes de você se comprometer com uma delas. Depois é só abrir o editor e começar a pintar.

Perguntas frequentes

Qual a diferença entre GridMap e TileMap na Godot?

O TileMap é para cenários 2D e trabalha com tiles planos. O GridMap é o equivalente 3D: ele encaixa malhas (meshes) de uma MeshLibrary em uma grade tridimensional, com células que também têm altura. A lógica de pintar células é parecida, mas o GridMap monta volumes 3D.

Como crio uma MeshLibrary para o GridMap?

Monte cada bloco como uma cena com um MeshInstance3D (e um StaticBody3D com CollisionShape3D se quiser colisão). No editor, abra Scene e use Convert To, MeshLibrary, escolha o arquivo .tres de saída. A Godot gera um item por cena filha e você já pode atribuir essa biblioteca ao GridMap.

O GridMap gera colisão automática dos blocos?

Sim, desde que cada bloco da MeshLibrary tenha a colisão embutida. Se você incluir um StaticBody3D com CollisionShape3D na cena do bloco antes de converter, o GridMap recria essa colisão em cada célula pintada, sem configuração extra.

Dá para editar o GridMap por código em tempo de execução?

Dá. Use set_cell_item(posicao, id) para colocar ou trocar um bloco e get_cell_item(posicao) para ler o que está em uma célula. A posição é um Vector3i em coordenadas de grade, não em unidades do mundo. Isso permite gerar dungeons procedurais ou destruir blocos em runtime.