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.

Ferramenta:Godot

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.