SuperAPI AI 工具集

debugging-techniques

编程与开发

查看项目

更新于 11-06 16:18

技能介绍

本技能介绍虚幻引擎中调试 C++ 与玩法代码的多种技术,核心思路是“按问题选工具”。

一、按问题选择工具 资料给出对照:想知道某个值或某段代码是否执行,用 UE_LOG / ensure;想知道物体在空间中的位置,用 DrawDebug* 辅助函数;想知道过去 N 秒发生了什么,用 Visual Logger;想知道 AI/玩法系统当前在想什么,用 Gameplay Debugger;需要崩溃排查或单步逻辑,用原生调试器(VS/Rider);关注帧时间、绘制调用、物理开销,则属于 profiling-and-optimization 的范畴。

二、日志与断言 对于“值是多少/路径是否执行”的问题,一行 UE_LOG 最快。玩法代码中不变量被破坏时,优先用 ensure 而非 check,以便编辑器存活并暴露问题而不崩溃。示例中 ensure 为非致命不变量,会记录调用栈、编辑器继续运行、默认每个会话每个调用点触发一次;check 为致命不变量,在开发构建中故意崩溃;checkf 可带格式化消息。资料注明这些宏位于 Runtime/Core/Public/Misc/AssertionMacros.h。

三、调试绘制(世界空间可视化) DrawDebug* 函数直接把几何体渲染到视口,包括线、球、盒、胶囊、文字标签、箭头、锥体等,无需 Actor 或组件,任何持有 UWorld* 的代码都可调用。示例包含 DrawDebugLine、DrawDebugSphere、DrawDebugString、DrawDebugCapsule、DrawDebugDirectionalArrow。多数函数共享参数:bPersistentLines(为 true 时保留至调用 FlushPersistentDebugLines)、LifeTime(可见秒数,-1 表示一帧)、DepthPriority(数值越高越靠前,SDPG_Foreground 可避免被几何体遮挡)、Thickness(线宽,单位为屏幕像素)。所有函数由 #if ENABLE_DRAW_DEBUG 保护,在 Shipping 中自动剥离,无需手动加 #if。

四、屏幕调试消息 对于无需 HUD 的瞬时读数,可用 GEngine->AddOnScreenDebugMessage,通过唯一的 Key 让同一消息每帧覆盖而非堆叠;INDEX_NONE 则每次调用追加新行。GEngine->ClearOnScreenDebugMessages() 可一次性清除全部消息。

五、Visual Logger(随时间记录事件) Visual Logger 按 Actor 记录带时间戳的文本与空间形状,录制后可在窗口中拖动时间轴,查看每个 Actor 在每一时刻看到、决定和绘制的内容,适合 AI 与间歇性 bug。资料建议对空间/时间类问题优先使用 UE_VLOG* 而非用 UE_LOG 刷屏。示例包含 UE_VLOG(文本)、UE_VLOG_LOCATION(世界位置球)、UE_VLOG_SEGMENT(两点间线段)、UE_VLOG_WIRESPHERE(线框球)、UE_CVLOG(条件变体)。这些宏在未定义 ENABLE_VISUAL_LOG 时为空操作,并会先判断 FVisualLogger::IsRecording(),未录制时无开销;UE_VLOG_UELOG 同时输出到 Visual Logger 与标准日志。

六、Gameplay Debugger(PIE 中的实时分类) Gameplay Debugger 是在 PIE 中按撇号键(')激活的游戏内叠加层,内置分类覆盖 AI 子系统(行为树、EQS、感知、导航)、能力等,也可注册自定义分类。资料给出注册自定义分类的代码(在模块 StartupModule 中通过 IGameplayDebugger::Get().RegisterCategory 注册,ShutdownModule 中注销),以及实现分类的类结构:CollectData 在服务器/单机运行并收集需复制的数据,DrawData 在客户端绘制;在 CollectData 中调用 AddTextLine 与 AddShape 填充数据。WITH_GAMEPLAY_DEBUGGER 默认在 Shipping 中未定义,需用它保护分类代码,并在 Build.cs 中添加 SetupGameplayDebuggerSupport(Target)。

七、原生调试器 可将 Visual Studio 或 Rider 附加到虚幻编辑器进程(或用 -debug 启动)。虚幻自带 .natvis 文件,使监视窗口能把 FString、FName、TArray、TMap、FVector 显示为可读值。实用习惯包括:在 VS 中对 FDebug::EnsureFailed 设置条件断点或启用“所有 C++ 异常时中断”;阅读崩溃调用栈时自上而下,项目代码中的第一帧通常就是坏指针或错误假设所在;checkNoEntry() 标记不应到达的代码路径,命中说明控制流有误而非数据有误。

八、Live Coding Live Coding(Ctrl+Alt+F11)可在不重启编辑器的情况下重新编译函数体,适合修改已有函数内部逻辑。它无法处理:增删 UPROPERTY/UFUNCTION 成员、改变类布局(新增成员变量、更改基类)、影响其他翻译单元的头文件改动。遇到这些情况需重启编辑器做完整热重载或使用 Unreal Build Tool。常见失败模式是结构性改动后 Live Coding“成功”,但旧 CDO 或蓝图实例保留过期布局,导致静默数据损坏或下一帧崩溃;崩溃后如有疑问应完整重建。

九、控制台命令与 CVar 用波浪键(~)打开控制台。资料列出常用开发命令:stat fps(帧率叠加)、stat unit(游戏/渲染/GPU 线程耗时)、stat game(各系统游戏线程开销)、stat ai(AI tick 开销)、showdebug ai(AI 状态叠加)、showdebug input(当前输入动作状态)、showdebug collision(碰撞通道可视化)、displayall ClassName PropertyName(对所有实例实时广播某 UPROPERTY 值)、dumpticks(列出所有 ticking Actor 及其 tick 组)、r.VisualizeOccludedPrimitives 1(高亮被剔除的图元)、ToggleDebugCamera(相机脱离 Pawn 自由飞行)、Slomo 0.1(时间放慢 10 倍)、t.MaxFPS 10(限制帧率以便慢动作观察)。CVar 命名遵循 r.(渲染)、s.(流送)、p.(物理)、t.(时间)、ai.*(AI)等模式,可用 DumpConsoleCommands 或控制台输入搜索。输入链上任意 UObject(Pawn、Controller、GameMode、CheatManager)的 Exec 函数可标记为 UFUNCTION(Exec) 并按名称从控制台调用,UCheatManager 是开发专用作弊的典型位置。

十、决策指南与注意事项 资料给出按 bug 类型选工具的对照表:值错误/未执行→UE_LOG/ensure;位置/形状/范围错误→DrawDebug* 或 UE_VLOG_LOCATION;AI 决策错误→Gameplay Debugger + Visual Logger;间歇/竞态/时序问题→Visual Logger(拖时间轴);崩溃/访问违例→原生调试器 + 调用栈;性能回退→profiling-and-optimization。 注意事项包括:DrawDebug* 与 AddOnScreenDebugMessage 在 Shipping 中会被剥离,不能依赖它们做玩法反馈;结构性改动后使用 Live Coding 会静默过期或立即崩溃,应做完整热重载重启;每 tick 用 UE_LOG 刷屏会产生 GB 级输出,空间/时间信息应改用 UE_VLOG*;该用 ensure 时用了 check 会导致编辑器崩溃并丢失未保存工作;UE_VLOG* 必须传入所有者(this),空所有者会静默丢弃条目;忘记 #if WITH_GAMEPLAY_DEBUGGER 会在 Shipping 中因模块被排除而链接错误;DrawDebugString 传入非空 TestBaseActor 时字符串位置相对该 Actor,Actor 移动会造成困惑,绝对位置应传 nullptr;LifeTime = -1.f 在 DrawDebugLine/DrawDebugSphere 中表示“使用默认时长”(一帧),并非永久保留,永久保留应设 bPersistentLines = true 再调用 FlushPersistentDebugLines 清除。

资料还列出引擎源码(UE 5.8)与官方文档链接,涵盖 DrawDebugHelpers.h、Engine.h、VisualLogger.h、GameplayDebugger.h、GameplayDebuggerCategory.h、AssertionMacros.h、CheatManager.h,以及 Visual Logger、Gameplay Debugger、Console Variables、Live Coding 的官方文档页面。