← Zurück zum Blog

Godot 4: Signal-Regeln im Prompt definieren, damit MCP die Health Bar verdrahtet

Bevor Sie Godot MCP in Cursor ansprechen, definieren Sie einen health_changed-Signalvertrag, damit das HUD ohne tiefe get_node-Pfade verbunden wird — Prompt-Vorlagen, GDScript-Beispiele, Anti-Patterns und Play-Akzeptanz.

Veröffentlicht
  • Godot MCP
  • Godot 4
  • signals
  • HUD
  • GDScript
  • Cursor
  • AI game development
  • tutorial

Der häufigste „KI hat meine Szene kaputt gemacht“-Fehler in Godot ist kein Syntaxfehler — es ist ein Health-Bar-Skript, das hart codiert:

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

Verschieben Sie den Baum oder instanziieren Sie Player als Kind-Szene, und dieser Pfad ist tot. Godot MCP folgt Ihrem Prompt zuverlässig — wenn Sie harte Pfade nicht verbieten, erfindet das Modell sie weiter.

Dieser Beitrag hat eine Aufgabe: In Cursor (oder Claude Code) zuerst einen Signalvertrag festlegen, dann MCP Player-Health mit der HUD-Bar verdrahten lassen. Keine Installationsanleitung, kein vollständiger Platformer-Build.

SchrittWas Sie tun
1Signal, Argumente, Emitter / Empfänger benennen
2MCP mit Constraints zum Bearbeiten von Skripten und Verbindungen prompten
3In Play akzeptieren; Prompt anhand von Anti-Patterns korrigieren

Verwandt:

Hintergrund: Scene organization — Kind-Szenen sollten Signale / Exports bereitstellen, keine tiefen Pfade.

Warum Signal-Regeln in den Prompt gehören

AnsatzKurzfristigNach Reorganisation
get_node("../Player/Health")SchnellBricht oft
@onready var bar = %HealthBar (Unique Name)In einer Szene okÜber Szenen hinweg weiterhin brüchig
signal health_changed(current, max) + connectZwei zusätzliche ZeilenHUD- und Player-Bäume können unabhängig geändert werden

MCP hat kein dauerhaftes „Architektur-Gedächtnis“, es sei denn, Sie wiederholen Constraints. Ein einfügbarer Vertragsblock ist günstiger, als harte Pfade aus jedem Diff zu entfernen.

Minimales Knoten-Skelett

Sie brauchen keine vollständige UI. v1 benötigt nur:

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

Benennung:

KnotenEmpfohlener NameHinweise
Player-RootPlayerBesitzt Health-Skript
HUD-LayerHUDCanvasLayer
BarHealthBarProgressBar; absolute HP oder max_value = 1 als Verhältnis

Wenn das HUD aus AI Studio stammt, benennen Sie es vor dem Verdrahten in stabile englische IDs um.

Signalvertrag (oben in jeden Prompt einfügen)

Behandeln Sie dies als Projektgesetz:

[Signalvertrag — Health]
1. Nur das Health-Skript auf Player emittiert:
   signal health_changed(current: float, max_health: float)
   Vergangenheits-/abgeschlossene Benennung; Argumente immer (current, max_health).
2. HUD-Bar-Skript verbindet nur dieses Signal und aktualisiert ProgressBar; kein get_node zu Player vom HUD aus.
3. Verboten: tiefe Cross-Scene-NodePaths, Autoload als Health-Bus (hier nicht nötig), Polling nach Player in _process.
4. Bevorzugt: Editor-Signalverbindungen oder @export Node / NodePath am HUD, dann .connect — niemals "/root/..." hart codieren.
5. Schaden und Heilung ändern nur Werte auf Player und emittieren; UI mutiert niemals HP.

Dieser Block ist der Kern des Artikels: Vertrag vor Implementierung.

Schritt 1: Read-only Smoke Test

Listen Sie die Kindnamen unter dem Root der aktuell bearbeiteten Szene auf. Ändern Sie keine Dateien oder Knoten.

Schreiben Sie erst, wenn Sie Player und HUD (oder Ihre Äquivalente) sehen.

Schritt 2: Player emittiert nur

Nach dem Vertrag anhängen:

[Signalvertrag — Health] (vollständigen Block einfügen)

In res://scripts/player_health.gd (bei Bedarf erstellen) und an Player anhängen:
- @export var max_health: float = 100.0
- var current: float
- signal health_changed(current: float, max_health: float)
- In _ready: current = max_health; health_changed einmal emittieren
- take_damage(amount), heal(amount); clamp 0..max_health; nach jeder Änderung emittieren
- Kein Verweis auf HUD; kein get_node in die UI
Speichern und Signal-Argumenttypen melden.

Referenzimplementierung:

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)

Temporäre Schaden-Taste (später löschen):

Fügen Sie temporär debug_damage.gd auf Player hinzu: Drücken von H ruft PlayerHealth.take_damage(10) auf demselben Knoten (oder Parent) auf. Nur für Verdrahtungs-Akzeptanz. HUD nicht anfassen.

Wenn das Skript auf dem Player-Root sitzt, ändern Sie extends Node entsprechend (z. B. CharacterBody2D), oder machen Sie PlayerHealth zu einem Kind Health — legen Sie einen Mount-Punkt im Prompt fest, damit MCP nicht raten muss.

Schritt 3: HUD abonniert über exportierte Referenz

[Signalvertrag — Health] (vollständigen Block einfügen)

Erstellen Sie res://scripts/hud_health.gd auf HUD oder HealthBar:
- @export var player_health: PlayerHealth
- @onready var bar: ProgressBar = $HealthBar  # nur wenn Skript auf HUD; Pfad bleibt innerhalb des HUD-Subtrees
- _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
  (oder Verhältnis: max_value = 1; value = current / max_health)
- Verboten: get_node zu Player; verboten: /root absolute Pfade
Weisen Sie dann player_health im Editor dem PlayerHealth (oder Health-Kind) von Player zu. Szene speichern.

Referenz:

extends CanvasLayer

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

func _ready() -> void:
	assert(player_health != null, "Assign PlayerHealth in the inspector")
	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 innerhalb des HUD ist in Ordnung — gleicher Subtree. Verboten ist ein tiefer Pfad über zu Player.

Editor „Node → Connect a Signal“ über MCP ist ebenfalls ok:

Über den Editor verbinden: Player (PlayerHealth) health_changed → HUD-Skript _on_health_changed. Keine NodePath-Strings von Hand schreiben.

Schritt 4: Play-Akzeptanz-Checkliste

  1. Beim Start: Bar voll (oder korrektes Verhältnis)
  2. H drücken: bar.value sinkt
  3. Bei 0: Bar leer; UI darf current nicht schreiben
  4. Nach heal: Bar steigt
  5. Player z. B. unter Entities reparenten und erneut Play: Bar aktualisiert sich weiter, wenn die Export-Referenz bestehen bleibt — das ist der Gewinn gegenüber harten Pfaden

Bricht es nach Reparenting, leere Export-Referenz korrigieren — MCP nicht nach „noch einem get_node“ fragen.

Akzeptanz-Prompt:

Aus Play-Fehlern diagnostizieren: wenn das Signal nie feuert, connect prüfen; wenn player_health null ist, nur Export korrigieren. Nicht mit absoluten get_node-Pfaden „reparieren“. Zuerst diagnostizieren; auf mein OK warten, bevor Sie bearbeiten.

Anti-Patterns: Prompt ändern, nicht mergen

Anti-PatternWarum es schadetZum Prompt hinzufügen
get_node("/root/Game/Player")Root-Pfad-Wechsel„Kein /root oder absoluter NodePath“
get_parent().get_node("Player")Geschwister-Kopplung„HUD darf Player-Geschwister-Layout nicht voraussetzen“
Autoload GlobalHealth.hpGlobaler Sammelordner„Kein neuer Autoload für diese Aufgabe“
HUD _process sucht PlayerLangsam und brüchig„Kein Polling; nur Signale“
Signal heißt update / set_hpVage, kollisionsanfällig„Signal muss health_changed heißen“

Handschreiben gewinnt weiterhin bei Hot-Path-Bewegung und komplexer Kampf-Mathematik; Health-Bar-Verdrahtung ist Boilerplate, wo ein vertraglich definierter MCP-Prompt meist günstiger ist. Siehe Godot MCP vs. manuelles Skripting.

Wiederverwendbares „Vertrag + Aufgabe“-Skelett

Namen für Mana / Boss-Bars tauschen:

[Signalvertrag]
- Emitter: <Knoten/Skript>
- signal <name>(...)
- Empfänger: <HUD-Methode>
- Verboten: absoluter NodePath, Autoload-Bus, _process-Polling

[Aufgabe]
1. …
2. …
3. Szene speichern; neue Signale und Verbindungen auflisten (Editor / .connect)

Zusammenfassung

  1. Harte Pfade sind ein Prompt-Loch, nicht „MCP kann kein Godot“
  2. health_changed(current, max_health) einfügen, bevor Sie nach Bearbeitungen fragen
  3. Player emittiert nur; HUD verbindet nur und aktualisiert ProgressBar
  4. Cross-Object-Links nutzen @export oder Editor-Signal-Connect — nicht /root/...
  5. Akzeptieren durch Reparenting von Player und Beobachten der Bar — nicht durch „Skript OK generiert“

Sie haben jetzt ein einfügbares Godot-MCP-Prompt-Regelwerk; Inventar, Quest-Log und Kill-Counter können dasselbe Muster wiederverwenden.

Weitere Guides, die Sie interessieren könnten