godot-debugging-profiling by thedivergentai/gd-agentic-skills
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-debugging-profiling利用 Godot 的调试工具高效查找和修复错误的专家指南。
print() — print(value) 毫无用处。请使用带有标签的 print("玩家生命值:", health)。if OS.is_debug_build() 包裹或使用自定义的 DEBUG 常量。打印语句会拖慢发布版本的运行速度。push_warning() 消息 — 警告信息提示了潜在的 bug(空引用、已弃用的 API)。在它们变成错误之前修复它们。assert() 进行运行时验证 — 断言在发布版本中会被禁用。对于运行时检查,请使用 if not condition: push_error()。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
--releaseEngine.capture_script_backtraces(true) 是廉价的 — 捕获局部变量会分配大量内存,并可能阻止对象被释放,从而导致人为的内存泄漏 [19]。Logger._log_message 重写中调用 push_error() 或 print() — 这会导致无限递归和崩溃,因为记录器会拦截自己的输出 [20]。OS.get_ticks_msec() 进行微基准测试 — 毫秒级精度不足以进行逻辑计时;对于微秒级精度,请始终使用 Time.get_ticks_usec() [22]。OBJECT_ORPHAN_NODE_COUNT 在生产环境中有效 — 此监视器严格仅用于调试;在发布版本中它会安全地返回 0,可能隐藏内存泄漏 [23]。print_stack() 或 print_debug() — 这些语句在调试器外部通常会被剥离或无效。对于生产环境,请使用结构化日志记录 [25]。_exit_tree() 中忘记注销 EditorDebuggerPlugin — 未能清理会在引擎的调试循环中留下“幽灵”连接 [27]。强制要求:在实现相应模式之前,请阅读相应的脚本。
使用 Time.get_ticks_usec() 进行微米级精度的执行计时,对于识别 CPU 微瓶颈至关重要。
使用内部性能监视器自动检测和记录“孤立节点”(已从场景树中移除但未释放的节点)。
以编程方式捕获详细的脚本调用栈回溯,包括用于深度崩溃报告的局部变量快照。
拦截底层的 C++ 引擎错误,并将其传输到自定义的后端日志或分析服务。
将特定于游戏的性能指标(AI 数量、子弹物理)直接暴露给 Godot 编辑器的“调试器”>“监视器”选项卡。
项目特定的调试器扩展,将自定义的可视化选项卡和数据注入到 Godot 底部面板。
使用互斥锁保护的记录器子类,用于从工作线程安全地将日志写入外部文件。
用于非可视化数据(如寻路节点、物理射线投射和局部 AI 影响图)的专业级可视化模式。
硬编码的断点触发器,用于在无效逻辑状态下以与团队无关的方式暂停执行。
用于调试移动设备和主机版游戏的内置命令控制台,在这些平台上无法访问标准终端输出。
请勿在发布版本中加载 debug_overlay.gd - 将其使用包裹在
if OS.is_debug_build()中。
# 基本打印
print("值: ", some_value)
# 格式化打印
print("玩家位于 %s,生命值 %d" % [position, health])
# 带调用者信息的打印
print_debug("此处为调试信息")
# 警告(非致命)
push_warning("这可能是个问题")
# 错误(非致命)
push_error("出错了!")
# 断言(在调试中致命)
assert(health > 0, "生命值不能为负数!")
设置断点:
breakpoint 关键字:func suspicious_function() -> void:
breakpoint # 执行在此处停止
var result := calculate_something()
调试 → 调试器 (Ctrl+Shift+D)
选项卡:
调试正在运行的游戏:
# ❌ 崩溃:空引用
$NonExistentNode.do_thing()
# ✅ 安全:先检查
var node := get_node_or_null("MaybeExists")
if node:
node.do_thing()
var _health: int = 100
var health: int:
get:
return _health
set(value):
print("生命值改变: %d → %d" % [_health, value])
print_stack() # 显示是谁改变了它
_health = value
func _draw() -> void:
if Engine.is_editor_hint():
draw_line(Vector2.ZERO, ray_direction * ray_length, Color.RED, 2.0)
# 使用 DebugDraw 插件或创建调试网格
func debug_draw_sphere(pos: Vector3, radius: float) -> void:
var mesh := SphereMesh.new()
mesh.radius = radius
var instance := MeshInstance3D.new()
instance.mesh = mesh
instance.global_position = pos
add_child(instance)
# 处理文件错误
func load_save() -> Dictionary:
if not FileAccess.file_exists(SAVE_PATH):
push_warning("未找到保存文件")
return {}
var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
if file == null:
push_error("打开保存文件失败: %s" % FileAccess.get_open_error())
return {}
var json := JSON.new()
var error := json.parse(file.get_as_text())
if error != OK:
push_error("JSON 解析错误: %s" % json.get_error_message())
return {}
return json.data
调试 → 性能分析器 (F3)
# 在 _process 中检查
func _process(delta: float) -> void:
print(Engine.get_frames_per_second()) # 监视 FPS
# 使用打印检查
func _exit_tree() -> void:
print("节点已释放: ", name)
# 使用组来跟踪
add_to_group("tracked")
print("活动对象: ", get_tree().get_nodes_in_group("tracked").size())
# 检查孤立节点
func check_orphans() -> void:
print("孤立节点: ", Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT))
# 运行时调试控制台
var console_visible := false
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.keycode == KEY_QUOTELEFT:
console_visible = not console_visible
$DebugConsole.visible = console_visible
const DEBUG := true
func debug_log(message: String) -> void:
if DEBUG:
print("[DEBUG] ", message)
# 仅在特定条件下中断
if player.health <= 0:
breakpoint
调试 → 远程调试 → 检查场景树
查看实时节点层次结构
每周安装次数
75
代码仓库
GitHub 星标数
68
首次出现
2026年2月10日
安全审计
安装于
gemini-cli72
codex72
opencode72
kimi-cli70
github-copilot70
amp70
Expert guidance for finding and fixing bugs efficiently with Godot's debugging tools.
print() without descriptive context — print(value) is useless. Use print("Player health:", health) with labels.if OS.is_debug_build() or use custom DEBUG const. Prints slow down release.push_warning() messages — Warnings indicate potential bugs (null refs, deprecated APIs). Fix them before they become errors.assert() for runtime validation in release — Asserts are disabled in release builds. Use if not condition: push_error() for runtime checks.--release flag.Engine.capture_script_backtraces(true) is cheap — Capturing locals allocates significant memory and can prevent objects from being deallocated, causing artificial leaks [19].push_error() or print() inside a custom Logger._log_message override — This causes infinite recursion and crashes as the logger intercepts its own output [20].OS.get_ticks_msec() for microbenchmarking — Milliseconds lack precision for logic timing; ALWAYS use Time.get_ticks_usec() for microsecond precision [22].OBJECT_ORPHAN_NODE_COUNT works in production — This monitor is strictly debug-only; it safely returns 0 in release builds, potentially hiding leaks [23].print_stack() or print_debug() in release builds — These are often stripped or useless outside the debugger. Use structured logging for production [25].EditorDebuggerPlugin in _exit_tree() — Failing to clean up leaves "ghost" connections in the engine's debugging loop [27].MANDATORY : Read the appropriate script before implementing the corresponding pattern.
Micrometer-precision execution timing using Time.get_ticks_usec(), essential for identifying CPU micro-bottlenecks.
Automated detection and logging of "Orphan Nodes" (nodes removed from tree but not freed) using internal Performance monitors.
Capturing detailed script backtraces programmatically, including local variable snapshots for deep crash reporting.
Intercepting underlying C++ engine errors and piping them to custom backend logs or analytics services.
Exposing game-specific performance metrics (AI counts, bullet physics) directly to the Godot Editor's Debugger > Monitors tab.
Project-specific debugger extensions that inject custom visual tabs and data into the Godot bottom panel.
Mutext-locked logger subclass for thread-safe writing of logs from worker threads to external files.
Pro-level visualization patterns for non-visual data like pathfinding nodes, physics raycasts, and local AI influence maps.
Hardcoded breakpoint triggers for halting execution on invalid logic states in a team-agnostic manner.
In-game command console for debugging mobile and console builds where standard terminal output is inaccessible.
Do NOT Load debug_overlay.gd in release builds - wrap usage in
if OS.is_debug_build().
# Basic print
print("Value: ", some_value)
# Formatted print
print("Player at %s with health %d" % [position, health])
# Print with caller info
print_debug("Debug info here")
# Warning (non-fatal)
push_warning("This might be a problem")
# Error (non-fatal)
push_error("Something went wrong!")
# Assert (fatal in debug)
assert(health > 0, "Health cannot be negative!")
Set Breakpoint:
Click line number gutter in script editor
Or use breakpoint keyword:
func suspicious_function() -> void: breakpoint # Execution stops here var result := calculate_something()
Debug → Debugger (Ctrl+Shift+D)
Tabs:
Debug running game:
# ❌ Crash: null reference
$NonExistentNode.do_thing()
# ✅ Safe: check first
var node := get_node_or_null("MaybeExists")
if node:
node.do_thing()
var _health: int = 100
var health: int:
get:
return _health
set(value):
print("Health changed: %d → %d" % [_health, value])
print_stack() # Show who changed it
_health = value
func _draw() -> void:
if Engine.is_editor_hint():
draw_line(Vector2.ZERO, ray_direction * ray_length, Color.RED, 2.0)
# Use DebugDraw addon or create debug meshes
func debug_draw_sphere(pos: Vector3, radius: float) -> void:
var mesh := SphereMesh.new()
mesh.radius = radius
var instance := MeshInstance3D.new()
instance.mesh = mesh
instance.global_position = pos
add_child(instance)
# Handle file errors
func load_save() -> Dictionary:
if not FileAccess.file_exists(SAVE_PATH):
push_warning("No save file found")
return {}
var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
if file == null:
push_error("Failed to open save: %s" % FileAccess.get_open_error())
return {}
var json := JSON.new()
var error := json.parse(file.get_as_text())
if error != OK:
push_error("JSON parse error: %s" % json.get_error_message())
return {}
return json.data
Debug → Profiler (F3)
# Check in _process
func _process(delta: float) -> void:
print(Engine.get_frames_per_second()) # Monitor FPS
# Check with print
func _exit_tree() -> void:
print("Node freed: ", name)
# Use groups to track
add_to_group("tracked")
print("Active objects: ", get_tree().get_nodes_in_group("tracked").size())
# Check for orphans
func check_orphans() -> void:
print("Orphan nodes: ", Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT))
# Runtime debug console
var console_visible := false
func _input(event: InputEvent) -> void:
if event is InputEventKey and event.keycode == KEY_QUOTELEFT:
console_visible = not console_visible
$DebugConsole.visible = console_visible
const DEBUG := true
func debug_log(message: String) -> void:
if DEBUG:
print("[DEBUG] ", message)
# Only break on specific condition
if player.health <= 0:
breakpoint
Debug → Remote Debug → Inspect scene tree
See live node hierarchy
Weekly Installs
75
Repository
GitHub Stars
68
First Seen
Feb 10, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli72
codex72
opencode72
kimi-cli70
github-copilot70
amp70
TanStack Query v5 完全指南:React 数据管理、乐观更新、离线支持
2,500 周安装
Box自动化工具包:通过Rube MCP实现文件上传、搜索、文件夹管理
69 周安装
Datadog自动化监控:通过Rube MCP与Composio实现指标、日志、仪表板管理
69 周安装
Intercom自动化指南:通过Rube MCP与Composio实现客户支持对话管理
69 周安装
二进制初步分析指南:使用ReVa工具快速识别恶意软件与逆向工程
69 周安装
PrivateInvestigator 道德人员查找工具 | 公开数据调查、反向搜索与背景研究
69 周安装
TorchTitan:PyTorch原生分布式大语言模型预训练平台,支持4D并行与H100 GPU加速
69 周安装