前言
由 Epic Games 推出的虚幻系列引擎,因其高效、全能、易获取、所见即所得等特性受到广大游戏开发者欢迎,市面上也不乏从入门到深度分析的教程。本系列主要面向虚幻引擎的初学者以及有一定实践经验的虚幻引擎游戏开发者,分享能够立即运用在自己项目中的实践技巧。本教程综合了个人的学习笔记、官方文档以及个人心得,水平不足之处,望读者反馈和指正。
本文是 UE 应用实例分享系列专栏的第六篇。
日志:用于 Debug
游戏开发中,常用的 Debug 手段有三种:其一是让函数返回错误码,由调用函数者处理错误;其二是运用编程语言提供的异常处理函数,将异常抛出或就地修复;第三种则是断言(Assert),对程序中那些不确定是否正确的东西进行检测,以便开发者在开发过程中尽早发现问题。
不过,假如程序本身运行正常,一些 Gameplay 表现却和我们的期待不符的时候,该如何判断呢?又或者,有时,我们无法使用 IDE 进行实时调试(比如,程序运行在云端服务器上)。这些情况下,我们可以查看日志来获取更多信息:通过日志,开发者可以知道人物是否释放了技能;服务器是否收到了数据;采集的物品是否进入了背包…… 我们将在本次分享中,为大家介绍如何打印虚幻引擎中的日志。
UE_LOG
UE_LOG 是虚幻引擎提供的 C++ 宏,用于打印日志到控制台或者引擎的 LOG 窗口中。在使用 C++ 对虚幻引擎的游戏进行编程时,我们经常使用这个宏进行日志打印,这也是在虚幻引擎中最常见的日志打印方式。
UE_LOG 提供了三个参数:
- 第一个参数:Log 类型(Categories)
- 第二个参数:Log 级别 - UE_LOG 日志级别
- 第三个参数:要打印的信息,包含一个 UE 的字符串,外加需要格式化的变量参数。
- %s - 字符串
- %d - 整数
- %f - 浮点数
使用 TEXT()
宏包裹的即为传入的字符串格式,可以在格式中使用上述参数来匹配后续传入的变量。类似 printf
函数的用法,我们可以打印变量中的数据。
示例:
UE_LOG(LogTemp, Warning, TEXT("My Float = %f, My String = %s"), MyFloat, *MyString);
日志级别
参考 Unreal Engine Community Wiki 给出的表格,引擎定义了 7 种不同的级别。
Verbosity Level | Printed in Console? | Printed in Editor's Log? | Notes |
---|---|---|---|
Fatal | Yes | N/A | Crashes the session, even if logging is disabled |
Error | Yes | Yes | Log text is coloured red |
Warning | Yes | Yes | Log text is coloured yellow |
Display | Yes | Yes | Log text is coloured grey |
Log | No | Yes | Log text is coloured grey |
Verbose | No | No | |
VeryVerbose | No | No |
对不同的日志级别进行分类有助于在繁多的日志中查找到我们需要的信息。上表中,日志的严重程度从上到下依次降低。在调试时,Error 级别以上的 Log 在执行打印语句时会中断程序运行。
接下来我们开始上手实践。
使用 C++ 在控制台打印日志
- 右键内容浏览器(Content Browser),新建一个继承自 Actor 的 C++ Class,取名为
LogActor
。后续我们会把它作为一个游戏对象放入 Level 中进行测试。
- 编辑
LogActor
的代码,添加一个函数用于测试打印 Log 的代码。我们把它标记为BlueprintCallable
,这代表着在蓝图里,我们可以调用这个函数。
// Header File UFUNCTION(BlueprintCallable) void PrintLog(); // Cpp File void ALogActor::PrintLog() { UE_LOG(LogTemp, Verbose, TEXT("I am a log from LogActor :)")); UE_LOG(LogTemp, Log, TEXT("I am a log from LogActor :)")); UE_LOG(LogTemp, Display, TEXT("I am a log from LogActor :)")); UE_LOG(LogTemp, Warning, TEXT("I am a log from LogActor :)")); }
- 继续编辑地图,创建一个继承自
LogActor
的蓝图,编辑蓝图添加一个按键事件,按下空格键(Space Bar)调用我们打印 Log 的函数,最后将它放入关卡中。这个步骤里,不要忘了在 Class Default 菜单中将 Input - Auto Receive Input 设置成 Player 0,否则键盘事件不会被触发。
- 打开下方的 Output Log 窗口,查看刚刚打印出来的内容:可以发现,Verbose 默认是没有打印出来的。Warning 会用黄色显示以示警告。进一步测试,如果是 Error 的话,还将以红色显示。
使用 C++ 在屏幕上打印日志
只在 UE 的日志窗口,或是在游戏的 Saved 文件夹中产生的 Log 文件里查看这些信息还是有些麻烦。有时候,我们希望日志直接反馈在屏幕上,这就需要用到 AddOnScreenDebugMessage
函数了。
下面是一个示例:
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::White, TEXT("This message will appear on the screen!"));
- 参数 1:信息 ID(uint64)。若指定 ID,下一次打印会替换前一次显示的信息,-1 代表每次都会打印。
- 参数 2:消息显示的时间。(float)
- 参数 3:消息显示的颜色。(FColor)
- 参数 4:消息的内容。(TEXT)
- 参数 5(可选):显示在屏幕上侧(true)还是下侧(false)。(Bool)
- 参数 6(可选):字体的缩放大小(2D vector)
同样,我们在刚刚的 C++ 文件中新建一个函数,使用上述示例进行调用。然后在蓝图中按下 F 键来调用它。
void ALogActor::PrintLogOnScreen() { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::White, TEXT("Welcome! This is a log print to our screen!")); }
在游戏中,Log 显示在了屏幕上,颜色是我们刚刚指定的白色,并且持续 5 秒后消失。
使用蓝图打印日志
用蓝图打印日志是临时调试最常用的方式之一,也最为易用。只需要使用 Print String 节点即可。Print String 节点本身提供了颜色,持续时间等可调整参数。
配合使用 Append String 可以拼接字符串,从而显示各种各样的内容。在这个示例中,我们打印当前这个 Actor 的名称。
再补充一个 TIPS:在 Print String 节点的字符串内容中以 Warning/Error 开头,可以打印这两种级别的 Log。在 Log 窗口查看则可以高亮显示。
自定义日志类型
最后介绍一下如何定义自己需要的日志类型。对日志进行分类,可以让开发者快速通过日志定位到出问题的模块和代码。
- 首先需要使用 UE 自带的宏来声明日志类型,这一步在头文件完成。
DECLARE_LOG_CATEGORY_EXTERN(CategoryName, DefaultVerbosity, Compile TimeVerbosity);
- 使用另一个宏来定义刚刚声明的类型,这一步在 Cpp 文件进行。
DEFINE_LOG_CATEGORY(CategoryName);
- 使用自己定义的类型。
UE_LOG(CategoryName, Log, TEXT("HEllo"));
示例:
DECLARE_LOG_CATEGORY_EXTERN(MyLog, Warning, All); DEFINE_LOG_CATEGORY(MyLog); UE_LOG(MyLog, Warning, TEXT("Hello"));
参考
[1]: 杰森·格雷戈瑞. 游戏引擎架构. 北京: 电子工业出版社. 2019.
[2]: Logging. Unreal Engine Community Wiki. 2022-09-09.
[3]: Unreal Engine Tip: Print String Output Log Tagging
图片:如无特别说明,文中图片均为作者自制
*本文内容系作者独立观点,不代表 indienova 立场。未经授权允许,请勿转载。
暂无关于此文章的评论。