← Torna al blog

Godot 4: Metti le regole dei segnali nel prompt così MCP collega la barra della salute

Prima di chiedere a Godot MCP in Cursor, definisci un contratto di segnale health_changed così l'HUD si connette senza percorsi get_node profondi—modelli di prompt, esempi GDScript, anti-pattern e accettazione in Play.

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

Introduzione

L’errore più comune “l’IA ha rotto la mia scena” in Godot non è un errore di sintassi—è uno script della barra della salute che hard-coda:

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

Riparenti l’albero o istanzia Player come scena figlia, e quel percorso muore. Godot MCP segue fedelmente il tuo prompt—se non proibisci i percorsi hard-coded, il modello continuerà a inventarli.

Questo post fa un solo lavoro: in Cursor (o Claude Code), dichiara prima un contratto di segnale, poi lascia che MCP colleghi la salute del giocatore alla barra HUD. Nessun tutorial di installazione, nessuna costruzione completa di platformer.

PassoCosa fai
1Nomina il segnale, gli argomenti, emettitore / ricevitore
2Prompt a MCP con vincoli per modificare script e connessioni
3Accetta in Play; correggi il prompt usando anti-pattern

Correlati:

Contesto: Organizzazione delle scene — le scene figlie dovrebbero esporre segnali / export, non percorsi profondi.

Perché le regole dei segnali appartengono al prompt

ApproccioBreve termineDopo la riorganizzazione
get_node("../Player/Health")VeloceSpesso si rompe
@onready var bar = %HealthBar (nome univoco)Ok in una scenaAncora fragile tra scene
signal health_changed(current, max) + connectDue righe in piùGli alberi HUD e Player possono cambiare indipendentemente

MCP non ha una “memoria architetturale” duratura a meno che tu non ripeta i vincoli. Un blocco di contratto incollabile è più economico che ripulire i percorsi hard-coded da ogni diff.

Scheletro minimo dei nodi

Non serve una UI completa. v1 ha bisogno solo di:

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

Nomi:

NodoNome suggeritoNote
Radice PlayerPlayerPossiede lo script della salute
Layer HUDHUDCanvasLayer
BarraHealthBarProgressBar; HP assoluti o max_value = 1 rapporto

Se l’HUD proviene da AI Studio, rinomina con ID inglesi stabili prima del collegamento.

Contratto di segnale (incolla all’inizio di ogni prompt)

Trattalo come legge di progetto:

[Contratto di segnale — salute]
1. Solo lo script della salute su Player emette:
   signal health_changed(current: float, max_health: float)
   Nome al passato / completato; argomenti sempre (current, max_health).
2. Lo script della barra HUD si connette solo a quel segnale e aggiorna ProgressBar; nessun get_node verso Player dall'HUD.
3. Vietati: NodePath profondi tra scene, Autoload come bus della salute (non necessario qui), polling per Player in _process.
4. Preferisci connessioni di segnale dall'editor, o @export Node / NodePath sull'HUD e poi .connect — mai hard-codare "/root/...".
5. Danno e cura cambiano solo i valori su Player ed emettono; la UI non muta mai gli HP.

Quel blocco è il punto di questo articolo: contratto prima dell’implementazione.

Passo 1: Test di sola lettura

Elenca i nomi dei figli sotto la radice della scena attualmente modificata. Non modificare file o nodi.

Scrivi solo quando vedi Player e HUD (o i tuoi equivalenti).

Passo 2: Player emette solo

Aggiungi dopo il contratto:

[Contratto di segnale — salute] (incolla il blocco completo)

In res://scripts/player_health.gd (crea se manca) e allegalo a Player:
- @export var max_health: float = 100.0
- var current: float
- signal health_changed(current: float, max_health: float)
- In _ready: current = max_health; emetti health_changed una volta
- take_damage(amount), heal(amount); clamp 0..max_health; emetti dopo ogni modifica
- Non fare riferimento all'HUD; non usare get_node verso la UI
Salva e riporta i tipi degli argomenti del segnale.

Implementazione di riferimento:

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)

Tasto danno temporaneo (elimina dopo):

Aggiungi debug_damage.gd temporaneo su Player: premendo H chiama PlayerHealth.take_damage(10) sullo stesso nodo (o genitore). Solo per accettazione del collegamento. Non toccare l'HUD.

Se lo script sta sulla radice Player, cambia extends Node per corrispondere (es. CharacterBody2D), oppure rendi PlayerHealth un figlio Health—scegli uno nel prompt così MCP non indovina il punto di montaggio.

Passo 3: L’HUD si sottoscrive tramite riferimento esportato

[Contratto di segnale — salute] (incolla il blocco completo)

Crea res://scripts/hud_health.gd su HUD o HealthBar:
- @export var player_health: PlayerHealth
- @onready var bar: ProgressBar = $HealthBar  # solo se lo script è su HUD; il percorso resta nel sottoalbero 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
  (o rapporto: max_value = 1; value = current / max_health)
- Vietato: get_node verso Player; vietati percorsi assoluti /root
Poi assegna l'export player_health al PlayerHealth di Player (o figlio Health) nell'editor. Salva la scena.

Riferimento:

extends CanvasLayer

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

func _ready() -> void:
	assert(player_health != null, "Assegna PlayerHealth nell'ispettore")
	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 l’HUD è ok—stesso sottoalbero. Vietato è un percorso profondo attraverso verso Player.

Anche l’editor “Node → Connect a Signal” tramite MCP è ok:

Connetti tramite l'editor: Player (PlayerHealth) health_changed → script HUD _on_health_changed. Non scrivere a mano stringhe NodePath.

Passo 4: Checklist di accettazione in Play

  1. All’ingresso: barra piena (o rapporto corretto)
  2. Premi H: bar.value scende
  3. A 0: barra vuota; la UI non deve scrivere current
  4. Dopo heal: la barra sale
  5. Riparenta Player sotto es. Entities e gioca di nuovo: la barra si aggiorna ancora se il riferimento export rimane—questo è il vantaggio rispetto ai percorsi hard-coded

Se si rompe dopo il riparenting, correggi l’export vuoto—non chiedere a MCP “un altro get_node”.

Prompt di accettazione:

Diagnostica dagli errori di Play: se il segnale non scatta mai, controlla la connessione; se player_health è null, correggi solo l'export. Non "correggere" con percorsi get_node assoluti. Diagnostica prima; attendi il mio OK prima di modificare.

Anti-pattern: cambia il prompt, non unire

Anti-patternPerché fa maleAggiungi al prompt
get_node("/root/Game/Player")Instabilità del percorso radice”Niente /root o NodePath assoluti”
get_parent().get_node("Player")Accoppiamento tra fratelli”L’HUD non deve assumere il layout dei fratelli di Player”
Autoload GlobalHealth.hpCassetto globale disordinato”Nessun nuovo Autoload per questo compito”
HUD _process che cerca PlayerLento e fragile”Niente polling; solo segnali”
Segnale chiamato update / set_hpVago, soggetto a collisioni”Il segnale deve chiamarsi health_changed”

Scrivere a mano vince ancora per movimento hot-path e matematica di combattimento complessa; il collegamento della barra della salute è boilerplate dove un prompt MCP contrattuale è di solito più economico. Vedi Godot MCP vs scripting manuale.

Scheletro riutilizzabile “contratto + compito”

Scambia i nomi per barre del mana / boss:

[Contratto di segnale]
- Emettitore: <nodo/script>
- signal <nome>(...)
- Ricevitore: <metodo HUD>
- Vietati: NodePath assoluti, bus Autoload, polling _process

[Compito]
1. …
2. …
3. Salva la scena; elenca i nuovi segnali e come si connettono (editor / .connect)
  1. I percorsi hard-coded sono un buco nel prompt, non “MCP non sa Godot”
  2. Incolla health_changed(current, max_health) prima di chiedere modifiche
  3. Player emette solo; HUD si connette solo e aggiorna ProgressBar
  4. I collegamenti tra oggetti usano @export o connessione segnale dall’editor—non /root/...
  5. Accetta riparentando Player e guardando la barra—non con “script generato OK”

Ora hai un set di regole di prompt Godot MCP incollabile; inventario, registro missioni e contatori di uccisioni possono riutilizzare lo stesso schema.

Altre guide che potrebbero interessarti