← Voltar ao blog

Godot 4: Coloque Regras de Sinais no Seu Prompt para o MCP Conectar a Barra de Vida

Antes de pedir ao Godot MCP no Cursor, defina um contrato de sinal health_changed para o HUD conectar sem caminhos get_node profundos—modelos de prompt, exemplos GDScript, anti-padrões e aceitação no Play.

Publicado
  • Godot MCP
  • Godot 4
  • signals
  • HUD
  • GDScript
  • Cursor
  • AI game development
  • tutorial

A falha mais comum de “IA quebrou minha cena” no Godot não é um erro de sintaxe—é um script de barra de vida que codifica:

$"/root/Game/Player/HitPoints".hp  # ou get_node("../../Player/...")

Reorganize a árvore ou instancie Player como uma cena filha, e esse caminho morre. Godot MCP segue seu prompt fielmente—se você não proibir caminhos fixos, o modelo continuará inventando-os.

Este post faz um trabalho: no Cursor (ou Claude Code), declare um contrato de sinal primeiro, depois deixe o MCP conectar a vida do jogador à barra do HUD. Sem tutorial de instalação, sem construção completa de plataforma.

PassoO que você faz
1Nomeie o sinal, argumentos, emissor / receptor
2Peça ao MCP com restrições para editar scripts e conexões
3Aceite no Play; corrija o prompt usando anti-padrões

Relacionados:

Contexto: Organização de cenas — cenas filhas devem expor sinais / exports, não caminhos profundos.

Por que regras de sinal pertencem ao prompt

AbordagemCurto prazoApós reorganização
get_node("../Player/Health")RápidoFrequentemente quebra
@onready var bar = %HealthBar (nome único)Ok em uma cenaAinda frágil entre cenas
signal health_changed(current, max) + connectDuas linhas extrasÁrvores do HUD e Player podem mudar independentemente

MCP não tem “memória de arquitetura” duradoura a menos que você repita restrições. Um bloco de contrato copiável é mais barato do que limpar caminhos fixos de cada diff.

Esqueleto mínimo de nós

Você não precisa de uma UI completa. A v1 só precisa de:

Game (Node2D / Node)
├── Player (CharacterBody2D)  ← player_health.gd
│   └── ...
└── HUD (CanvasLayer)
    └── HealthBar (ProgressBar ou TextureProgressBar)  ← hud_health.gd

Nomenclatura:

NóNome sugeridoNotas
Raiz do PlayerPlayerPossui o script de vida
Camada HUDHUDCanvasLayer
BarraHealthBarProgressBar; HP absoluto ou max_value = 1 proporção

Se o HUD veio do AI Studio, renomeie para IDs estáveis em inglês antes de conectar.

Contrato de sinal (cole no topo de cada prompt)

Trate isso como lei do projeto:

[Contrato de sinal — vida]
1. Apenas o script de vida no Player emite:
   signal health_changed(current: float, max_health: float)
   Nome no passado / concluído; argumentos sempre (current, max_health).
2. O script da barra do HUD apenas conecta esse sinal e atualiza a ProgressBar; sem get_node para Player a partir do HUD.
3. Proibido: NodePaths profundos entre cenas, Autoload como barramento de vida (não necessário aqui), polling por Player no _process.
4. Prefira conexões de sinal no editor, ou @export Node / NodePath no HUD e depois .connect — nunca codifique "/root/...".
5. Dano e cura apenas mudam valores no Player e emitem; a UI nunca muta HP.

Esse bloco é o ponto deste artigo: contrato antes da implementação.

Passo 1: Teste de fumaça somente leitura

Liste os nomes dos filhos sob a raiz da cena atualmente editada. Não modifique nenhum arquivo ou nó.

Só escreva quando vir Player e HUD (ou seus equivalentes).

Passo 2: Player emite apenas

Anexe após o contrato:

[Contrato de sinal — vida] (cole o bloco completo)

Em res://scripts/player_health.gd (crie se não existir) e anexe ao Player:
- @export var max_health: float = 100.0
- var current: float
- signal health_changed(current: float, max_health: float)
- Em _ready: current = max_health; emita health_changed uma vez
- take_damage(amount), heal(amount); limite 0..max_health; emita após cada mudança
- Não referencie HUD; não use get_node para UI
Salve e reporte os tipos dos argumentos do sinal.

Implementação de referência:

extends Node
class_name PlayerHealth

signal health_changed(current: float, max_health: float)

@export var max_health: float = 100.0
var current: float

func _ready() -> void:
	current = max_health
	health_changed.emit(current, max_health)

func take_damage(amount: float) -> void:
	if amount <= 0.0 or current <= 0.0:
		return
	current = maxf(0.0, current - amount)
	health_changed.emit(current, max_health)

func heal(amount: float) -> void:
	if amount <= 0.0 or current <= 0.0:
		return
	current = minf(max_health, current + amount)
	health_changed.emit(current, max_health)

Tecla de dano temporária (apague depois):

Adicione debug_damage.gd temporário no Player: pressionar H chama PlayerHealth.take_damage(10) no mesmo nó (ou pai). Apenas para aceitação da conexão. Não toque no HUD.

Se o script estiver na raiz do Player, mude extends Node para corresponder (ex.: CharacterBody2D), ou faça PlayerHealth um filho Health—escolha um no prompt para o MCP não adivinhar o ponto de montagem.

Passo 3: HUD assina via referência exportada

[Contrato de sinal — vida] (cole o bloco completo)

Crie res://scripts/hud_health.gd no HUD ou HealthBar:
- @export var player_health: PlayerHealth
- @onready var bar: ProgressBar = $HealthBar  # apenas se o script estiver no HUD; caminho permanece dentro da subárvore do HUD
- _ready: assert player_health != null; player_health.health_changed.connect(_on_health_changed)
- _on_health_changed(current, max_health): bar.max_value = max_health; bar.value = current
  (ou proporção: max_value = 1; value = current / max_health)
- Proibido: get_node para Player; proibido: caminhos absolutos /root
Depois atribua o player_health exportado ao PlayerHealth do Player (ou filho Health) no editor. Salve a cena.

Referência:

extends CanvasLayer

@export var player_health: PlayerHealth
@onready var bar: ProgressBar = $HealthBar

func _ready() -> void:
	assert(player_health != null, "Atribua PlayerHealth no inspetor")
	player_health.health_changed.connect(_on_health_changed)

func _on_health_changed(current: float, max_health: float) -> void:
	bar.max_value = max_health
	bar.value = current

$HealthBar dentro do HUD é ok—mesma subárvore. Proibido é um caminho profundo através para Player.

Conexão via editor “Nó → Conectar um Sinal” via MCP também é ok:

Conecte via editor: Player (PlayerHealth) health_changed → script do HUD _on_health_changed. Não escreva strings NodePath manualmente.

Passo 4: Checklist de aceitação no Play

  1. Ao entrar: barra cheia (ou proporção correta)
  2. Pressione H: bar.value cai
  3. Até 0: barra vazia; UI não deve escrever current
  4. Após heal: barra sobe
  5. Reorganize Player sob ex.: Entities e jogue novamente: a barra ainda atualiza se a referência exportada permanecer—essa é a vitória vs caminhos fixos

Se quebrar após reorganizar, corrija o export vazio—não peça ao MCP por “outro get_node”.

Prompt de aceitação:

Diagnostique a partir dos erros do Play: se o sinal nunca dispara, verifique a conexão; se player_health for nulo, apenas corrija o export. Não "corrija" com caminhos get_node absolutos. Diagnostique primeiro; aguarde meu OK antes de editar.

Anti-padrões: mude o prompt, não faça merge

Anti-padrãoPor que prejudicaAdicione ao prompt
get_node("/root/Game/Player")Mudança de caminho raiz”Sem /root ou NodePath absoluto”
get_parent().get_node("Player")Acoplamento entre irmãos”HUD não deve assumir layout de irmão do Player”
Autoload GlobalHealth.hpGaveta global de lixo”Sem novo Autoload para esta tarefa”
HUD _process procurando PlayerLento e frágil”Sem polling; apenas sinais”
Sinal nomeado update / set_hpVago, propenso a colisão”Sinal deve ser health_changed”

Escrever manualmente ainda vence para movimento de alto desempenho e matemática de combate complexa; conexão de barra de vida é boilerplate onde um prompt MCP contratado é geralmente mais barato. Veja Godot MCP vs script manual.

Esqueleto reutilizável “contrato + tarefa”

Troque nomes para barras de mana / chefe:

[Contrato de sinal]
- Emissor: <nó/script>
- signal <nome>(...)
- Receptor: <método do HUD>
- Proibido: NodePath absoluto, barramento Autoload, polling _process

[Tarefa]
1. …
2. …
3. Salve a cena; liste novos sinais e como eles conectam (editor / .connect)

Resumo

  1. Caminhos fixos são um buraco no prompt, não “MCP não sabe Godot”
  2. Cole health_changed(current, max_health) antes de pedir edições
  3. Player apenas emite; HUD apenas conecta e atualiza ProgressBar
  4. Links entre objetos usam @export ou conexão de sinal no editor—não /root/...
  5. Aceite reorganizando Player e observando a barra—não por “script gerado OK”

Agora você tem um conjunto de regras de prompt Godot MCP copiável; inventário, registro de missões e contadores de abates podem reutilizar o mesmo padrão.

Mais guias que podem interessar