Voltar para o Blog
Quest Log

@tool na Godot 4: rodar código GDScript no editor

Editor da Godot 4 mostrando uma grade gerada em tempo real por um tool script

Aprenda a usar tool script com a anotação @tool na Godot 4 para rodar código GDScript dentro do editor, criar previews, gizmos e validar dados sem apertar Play.

Toda vez que você aperta Play na Godot só para conferir se um nó ficou no lugar certo, você perde alguns segundos que, somados, viram horas. A anotação @tool existe justamente para acabar com esse vaivém: ela faz o seu GDScript rodar código dentro do editor, e não apenas quando o jogo está em execução. Com um tool script bem escrito, você vê a grade se desenhar, o preview se atualizar e o gizmo seguir o valor exportado em tempo real, sem sair da tela de edição. Neste post da CursoGame.Dev você vai entender o que a @tool faz de verdade, quando ela vale a pena, como separar o comportamento de editor do de jogo e quais pegadinhas podem congelar a sua Godot 4 no meio do trabalho.

O que a anotação @tool faz de verdade

Por padrão, o código de um nó só ganha vida quando o jogo está rodando. Você aperta Play, a cena instancia, o _ready dispara, o _process roda a cada frame. No editor, o mesmo script fica dormindo: a Godot conhece as suas variáveis e métodos, mas não executa nada.

Quando você coloca @tool na primeira linha do arquivo, esse contrato muda. A Godot passa a rodar aquele script também dentro do editor. Isso significa que o _ready executa quando a cena abre no editor, o _process pode rodar enquanto você mexe na cena, e os setters das suas @export disparam assim que você digita um valor novo no Inspetor. É o mesmo código, só que agora ele acorda em dois lugares.

A anotação vai sozinha, no topo absoluto do arquivo, antes até do extends:

@tool
extends Node2D

@export var raio: float = 32.0

Essa ordem importa. A @tool precisa ser a primeira coisa que a Godot lê. Se você colocar depois do extends, o editor reclama, e o script não roda como ferramenta.

Quando usar um tool script

Nem todo script deveria ser @tool. A anotação é uma ferramenta de autoria, então ela brilha nos casos em que você quer ver ou preparar algo enquanto monta a cena, não durante a jogatina. Alguns cenários clássicos:

  • Previews em tempo real. Um nó que mostra a área de alcance de uma torre, o raio de um som ou o campo de visão de um inimigo, tudo isso atualizado no instante em que você muda o valor exportado.
  • Gizmos e desenho no editor. Usando _draw em um nó 2D marcado com @tool, você desenha linhas, círculos e rótulos que ajudam a posicionar as coisas, sem que apareçam no jogo final.
  • Geradores de nós. Um script que cria e organiza filhos automaticamente: uma grade de tiles, uma fileira de colunas, um caminho de waypoints. Você configura os parâmetros e a estrutura se monta sozinha na árvore.
  • Validação de dados de designer. Se um artista ou level designer preenche uma @export com um valor absurdo, o tool script pode avisar na hora, com um push_warning, em vez de deixar o bug escapar para o jogo.

Repare no fio condutor: são tarefas de quem está construindo a cena. Lógica de combate, física, save, input do jogador, nada disso deveria depender de @tool. Esse tipo de coisa mora no jogo rodando, e é aí que entra o cuidado de separar os dois mundos.

Rodar no editor não é rodar no jogo

Aqui está o detalhe que pega a maioria das pessoas de surpresa. Depois de marcar o script com @tool, o código roda nos dois lugares: no editor e no jogo. Se você escrever um _process que move o nó, ele vai se mexer no editor também, o que raramente é o que você quer.

A Godot resolve isso com uma função simples:

func _process(delta: float) -> void:
    if Engine.is_editor_hint():
        # Estou dentro do editor de cena
        return
    # Daqui para baixo, só quando o jogo está rodando
    position.x += 100.0 * delta

Engine.is_editor_hint() devolve true quando o código está rodando dentro do editor e false quando o jogo está de fato em execução. Ela é o interruptor que separa o comportamento de autoria do comportamento de gameplay.

A regra prática que eu sigo é a seguinte. Envolva em if Engine.is_editor_hint(): tudo que serve para o preview e a autoria. Envolva em if not Engine.is_editor_hint(): tudo que é lógica de jogo de verdade: movimento, dano, timers de gameplay, chamadas para o seu singleton de estado global via autoload. Assim o mesmo script se comporta como ferramenta enquanto você edita e como código de jogo quando o jogador aperta start.

Exemplo prático: um gerador de grade no editor

Chega de teoria. Vamos montar um nó que desenha uma grade de pontos no editor e a atualiza sozinha conforme você muda as @export. É um dos usos mais úteis de @tool: você posiciona objetos, alinha tiles ou visualiza um espaçamento sem precisar rodar o jogo.

@tool
extends Node2D

@export var colunas: int = 8:
    set(valor):
        colunas = max(1, valor)
        queue_redraw()

@export var linhas: int = 5:
    set(valor):
        linhas = max(1, valor)
        queue_redraw()

@export var espacamento: float = 48.0:
    set(valor):
        espacamento = max(1.0, valor)
        queue_redraw()

@export var cor: Color = Color.CYAN:
    set(valor):
        cor = valor
        queue_redraw()

Cada @export tem um set que faz duas coisas: guarda o valor (com um mínimo de segurança, para ninguém passar zero coluna) e chama queue_redraw(). Esse queue_redraw() é o que pede para a Godot redesenhar o nó no próximo frame. Como o script é @tool, esse redesenho acontece no editor, na hora em que você digita.

Agora o desenho em si, no método _draw:

func _draw() -> void:
    var raio_ponto: float = 3.0
    for coluna in range(colunas):
        for linha in range(linhas):
            var ponto: Vector2 = Vector2(
                coluna * espacamento,
                linha * espacamento
            )
            draw_circle(ponto, raio_ponto, cor)

Salve o script, adicione o nó a uma cena e olhe o resultado. Ao arrastar o campo colunas no Inspetor, a grade cresce na sua frente. Ao mudar o espacamento, os pontos se afastam. Nenhum Play envolvido. Isso é @tool fazendo o trabalho: rodar código GDScript no editor para dar um retorno visual imediato.

Se você quisesse que essa grade também aparecesse no jogo, bastaria deixar o _draw como está. Mas se ela é só um guia de autoria, você pode proteger o desenho:

func _draw() -> void:
    if not Engine.is_editor_hint():
        return
    var raio_ponto: float = 3.0
    for coluna in range(colunas):
        for linha in range(linhas):
            var ponto: Vector2 = Vector2(
                coluna * espacamento,
                linha * espacamento
            )
            draw_circle(ponto, raio_ponto, cor)

Com esse return, a grade vira um andaime que só existe enquanto você edita e some quando o jogador está no controle.

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

Perguntas frequentes

O que a anotação @tool faz na Godot 4?

A anotação @tool no topo do script diz para a Godot rodar aquele GDScript também dentro do editor, não apenas durante o jogo. Assim o _ready, o _process e os setters de @export executam enquanto você edita a cena, permitindo previews e ferramentas de autoria.

Qual a diferença entre rodar no editor e rodar no jogo?

Sem @tool, o script só executa quando você aperta Play. Com @tool, o mesmo código roda nas duas situações. Para separar os comportamentos você usa Engine.is_editor_hint(), que devolve true dentro do editor e false no jogo rodando.

Para que serve Engine.is_editor_hint()?

Serve para proteger blocos que só devem acontecer em uma das situações. Você envolve a lógica de física, input ou save do jogo em if not Engine.is_editor_hint(), e a lógica de preview visual em if Engine.is_editor_hint(), evitando efeitos indesejados enquanto edita a cena.

Um tool script pode travar o editor da Godot?

Pode. Um loop infinito, um while sem condição de saída ou uma recursão pesada dentro do código de editor congela a Godot inteira, porque roda no mesmo processo. Salve com frequência e teste a lógica pesada primeiro no jogo antes de marcar com @tool.

Preciso de @tool para desenhar gizmos personalizados?

Para gizmos 2D via _draw ou para atualizar visuais no editor conforme uma @export muda, sim, o @tool é o caminho. Para gizmos 3D mais avançados existe a API EditorNode3DGizmoPlugin, que também depende de plugin de editor, mas o @tool cobre a maioria dos casos do dia a dia.