← Về blog

Godot 4: Đặt Quy Tắc Tín Hiệu Trong Prompt Để MCP Kết Nối Thanh Máu

Trước khi yêu cầu Godot MCP trong Cursor, hãy định nghĩa hợp đồng tín hiệu health_changed để HUD kết nối mà không cần đường dẫn get_node sâu—mẫu prompt, mã GDScript, phản mẫu và kiểm tra Play.

Đăng ngày
  • Godot MCP
  • Godot 4
  • signals
  • HUD
  • GDScript
  • Cursor
  • AI game development
  • tutorial

Mô tả

Lỗi phổ biến nhất “AI làm hỏng scene của tôi” trong Godot không phải là lỗi cú pháp—mà là script thanh máu viết cứng:

$"/root/Game/Player/HitPoints".hp  # hoặc get_node("../../Player/...")

Thay đổi cấu trúc cây hoặc tạo Player như một scene con, và đường dẫn đó sẽ chết. Godot MCP tuân theo prompt của bạn một cách trung thành—nếu bạn không cấm các đường dẫn cứng, mô hình sẽ tiếp tục tạo ra chúng.

Bài viết này chỉ làm một việc: trong Cursor (hoặc Claude Code), hãy nêu rõ hợp đồng tín hiệu trước, sau đó để MCP kết nối máu của người chơi với thanh HUD. Không có hướng dẫn cài đặt, không có bản dựng platformer đầy đủ.

BướcViệc bạn làm
1Đặt tên tín hiệu, tham số, bên phát / bên nhận
2Yêu cầu MCP với các ràng buộc để chỉnh sửa script và kết nối
3Chấp nhận trong Play; sửa prompt bằng các phản mẫu

Liên quan:

Bối cảnh: Tổ chức scene — các scene con nên hiển thị tín hiệu / export, không phải đường dẫn sâu.

Tại sao quy tắc tín hiệu nên nằm trong prompt

Cách tiếp cậnNgắn hạnSau khi tổ chức lại
get_node("../Player/Health")NhanhThường hỏng
@onready var bar = %HealthBar (tên duy nhất)Ổn trong một sceneVẫn mong manh giữa các scene
signal health_changed(current, max) + connectThêm hai dòngCây HUD và Player có thể thay đổi độc lập

MCP không có “bộ nhớ kiến trúc” lâu dài trừ khi bạn lặp lại các ràng buộc. Một khối hợp đồng có thể dán rẻ hơn việc dọn dẹp các đường dẫn cứng khỏi mọi diff.

Khung node tối thiểu

Bạn không cần UI đầy đủ. Phiên bản v1 chỉ cần:

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

Đặt tên:

NodeTên gợi ýGhi chú
Gốc PlayerPlayerSở hữu script máu
Lớp HUDHUDCanvasLayer
ThanhHealthBarProgressBar; HP tuyệt đối hoặc max_value = 1 tỷ lệ

Nếu HUD đến từ AI Studio, hãy đổi tên thành ID tiếng Anh ổn định trước khi kết nối.

Hợp đồng tín hiệu (dán ở đầu mỗi prompt)

Coi đây là luật của dự án:

[Hợp đồng tín hiệu — máu]
1. Chỉ script máu trên Player phát:
   signal health_changed(current: float, max_health: float)
   Đặt tên ở thì quá khứ / hoàn thành; tham số luôn (current, max_health).
2. Script thanh HUD chỉ kết nối tín hiệu đó và cập nhật ProgressBar; không get_node đến Player từ HUD.
3. Cấm: NodePath xuyên scene sâu, Autoload như một bus máu (không cần ở đây), thăm dò Player trong _process.
4. Ưu tiên kết nối tín hiệu trong editor, hoặc @export Node / NodePath trên HUD rồi .connect — không bao giờ viết cứng "/root/...".
5. Sát thương và hồi máu chỉ thay đổi giá trị trên Player và phát tín hiệu; UI không bao giờ thay đổi HP.

Khối đó là điểm chính của bài viết này: hợp đồng trước khi triển khai.

Bước 1: Kiểm tra khói chỉ đọc

Liệt kê tên các node con dưới gốc của scene đang chỉnh sửa. Không sửa đổi bất kỳ tệp hoặc node nào.

Chỉ viết khi bạn thấy Player và HUD (hoặc tương đương).

Bước 2: Player chỉ phát

Thêm sau hợp đồng:

[Hợp đồng tín hiệu — máu] (dán toàn bộ khối)

Trong res://scripts/player_health.gd (tạo nếu thiếu) và gắn vào Player:
- @export var max_health: float = 100.0
- var current: float
- signal health_changed(current: float, max_health: float)
- Trong _ready: current = max_health; phát health_changed một lần
- take_damage(amount), heal(amount); giới hạn 0..max_health; phát sau mỗi thay đổi
- Không tham chiếu HUD; không get_node vào UI
Lưu và báo cáo kiểu tham số tín hiệu.

Triển khai tham khảo:

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)

Phím sát thương tạm thời (xóa sau):

Thêm debug_damage.gd tạm thời trên Player: nhấn H gọi PlayerHealth.take_damage(10) trên cùng node (hoặc cha). Chỉ để chấp nhận kết nối. Không đụng đến HUD.

Nếu script nằm trên gốc Player, hãy đổi extends Node cho phù hợp (ví dụ CharacterBody2D), hoặc tạo PlayerHealth như một node con Health—chọn một trong prompt để MCP không đoán điểm gắn.

Bước 3: HUD đăng ký qua tham chiếu export

[Hợp đồng tín hiệu — máu] (dán toàn bộ khối)

Tạo res://scripts/hud_health.gd trên HUD hoặc HealthBar:
- @export var player_health: PlayerHealth
- @onready var bar: ProgressBar = $HealthBar  # chỉ khi script trên HUD; đường dẫn nằm trong cây con 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
  (hoặc tỷ lệ: max_value = 1; value = current / max_health)
- Cấm: get_node đến Player; cấm: đường dẫn tuyệt đối /root
Sau đó gán player_health export cho PlayerHealth (hoặc node con Health) của Player trong editor. Lưu scene.

Tham khảo:

extends CanvasLayer

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

func _ready() -> void:
	assert(player_health != null, "Gán PlayerHealth trong 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 bên trong HUD là ổn—cùng cây con. Cấm là đường dẫn sâu xuyên đến Player.

Editor “Node → Kết nối tín hiệu” qua MCP cũng ổn:

Kết nối qua editor: Player (PlayerHealth) health_changed → script HUD _on_health_changed. Không viết tay chuỗi NodePath.

Bước 4: Danh sách kiểm tra chấp nhận trong Play

  1. Khi vào: thanh đầy (hoặc tỷ lệ đúng)
  2. Nhấn H: bar.value giảm
  3. Đến 0: thanh trống; UI không được ghi current
  4. Sau heal: thanh tăng
  5. Đổi cha Player thành ví dụ Entities và Play lại: thanh vẫn cập nhật nếu tham chiếu export còn—đó là chiến thắng so với đường dẫn cứng

Nếu hỏng sau khi đổi cha, hãy sửa export trống—đừng yêu cầu MCP “get_node khác”.

Prompt chấp nhận:

Chẩn đoán từ lỗi Play: nếu tín hiệu không bao giờ phát, kiểm tra kết nối; nếu player_health null, chỉ sửa export. Không "sửa" bằng đường dẫn get_node tuyệt đối. Chẩn đoán trước; chờ tôi OK trước khi chỉnh sửa.

Phản mẫu: thay đổi prompt, không hợp nhất

Phản mẫuTại sao có hạiThêm vào prompt
get_node("/root/Game/Player")Thay đổi đường dẫn gốc”Không /root hoặc NodePath tuyệt đối”
get_parent().get_node("Player")Ghép cặp anh em”HUD không được giả định bố cục anh em của Player”
Autoload GlobalHealth.hpNgăn kéo rác toàn cục”Không Autoload mới cho nhiệm vụ này”
HUD _process tìm PlayerChậm và mong manh”Không thăm dò; chỉ tín hiệu”
Tín hiệu tên update / set_hpMơ hồ, dễ xung đột”Tín hiệu phải là health_changed”

Viết tay vẫn thắng cho chuyển động đường đua và toán chiến đấu phức tạp; kết nối thanh máu là boilerplate nơi prompt MCP có hợp đồng thường rẻ hơn. Xem Godot MCP so với viết script thủ công.

Khung “hợp đồng + nhiệm vụ” tái sử dụng

Đổi tên cho thanh mana / thanh boss:

[Hợp đồng tín hiệu]
- Bên phát: <node/script>
- signal <tên>(...)
- Bên nhận: <phương thức HUD>
- Cấm: NodePath tuyệt đối, bus Autoload, thăm dò _process

[Nhiệm vụ]
1. …
2. …
3. Lưu scene; liệt kê tín hiệu mới và cách chúng kết nối (editor / .connect)

Tóm tắt

  1. Đường dẫn cứng là lỗ hổng prompt, không phải “MCP không làm được Godot”
  2. Dán health_changed(current, max_health) trước khi yêu cầu chỉnh sửa
  3. Player chỉ phát; HUD chỉ kết nối và cập nhật ProgressBar
  4. Liên kết giữa các đối tượng dùng @export hoặc kết nối tín hiệu trong editor—không phải /root/...
  5. Chấp nhận bằng cách đổi cha Player và quan sát thanh—không phải “script tạo OK”

Bây giờ bạn đã có bộ quy tắc prompt Godot MCP có thể dán; kho đồ, nhật ký nhiệm vụ và bộ đếm kill có thể tái sử dụng cùng mẫu này.

Các bài hướng dẫn bạn có thể thích