虚幻引擎应用实例分享(九):控制台变量

作者:Dluck
2023-10-13
2 0 0

前言

由 Epic Games 推出的虚幻系列引擎,因其高效、全能、易获取、所见即所得等特性受到广大游戏开发者欢迎,市面上也不乏从入门到深度分析的教程。本系列主要面向虚幻引擎的初学者以及有一定实践经验的虚幻引擎游戏开发者,分享能够立即运用在自己项目中的实践技巧。本教程综合了个人的学习笔记、官方文档以及个人心得,水平不足之处,望读者反馈和指正。

本文是 UE 应用实例分享系列专栏的第九篇。

灵活开发:控制台变量

游戏开发中,引擎通常会提供丰富的可配置选项,从画面效果到游戏功能、音效、调试等,各方面都有涉及。这些配置信息一般都实现为某个单例类或者全局变量,在对应位置进行读写。 而众多设置入口中,控制台变量是一种相对特殊的存在,它可以通过命令行参数或者特定的按键触发,直接在游戏运行时修改某些参数值,而无需重新编译。这种灵活性为游戏开发者提供了巨大的便利。

控制台变量在游戏开发中有着广泛的应用,比如快速调试和测试,也可用于实现一些特殊功能。掌握了控制台变量的相关知识,可以让我们更加灵活地进行开发工作,提高效率。

定义控制台变量

虚幻引擎中的控制台变量的定义通常可以使用 TAutoConsoleVariable 或者 IConsoleManager::Get().RegisterConsoleVariable 两种方法实现。以下是它们的简单使用方法:

  • TAutoConsoleVariable 方法
static TAutoConsoleVariable CVarName(
    TEXT("ConsoleVarName"), // 控制台变量名称
    DefaultValue, // 默认值
    TEXT("Description"), // 描述信息
    ECVF_Flags // 控制台变量标志
);
  • IConsoleManager::Get().RegisterConsoleVariable 方法
IConsoleManager::Get().RegisterConsoleVariable(
    TEXT("ConsoleVarName"), // 控制台变量名称
    DefaultValue, // 默认值
    TEXT("Description"), // 描述信息
    ECVF_Flags // 控制台变量标志
);

其中 EConsoleVariableFlags 是一个枚举类型,表示控制台变量的一些特殊标志,包括但不限于:

  • ECVF_Cheat:表示该变量只在作弊模式下有效;
  • ECVF_Unregistered:表示该变量未被注册,生成时不会在控制台中显示;
  • ECVF_RenderThreadSafe:表示该变量可以在渲染线程中被访问;
  • ECVF_Scalability:表示该变量可以根据画面质量自动调整。

生成控制台变量时,可以使用这些标志对其进行特殊配置。

需要注意的是,控制台变量的定义应该在游戏引擎的初始化过程中进行。使用 IConsoleManager 注册方式的话,通常选择在游戏初始化阶段的代码中进行定义。

读取控制台变量

我们有两种方式来读取控制台变量。

第一种方式是使用控制台变量对象来获取值。例如,我们可以使用以下代码获取名为 CVarRefractionQuality 的控制台变量的值:

extern TAutoConsoleVariable<int32> CVarRefractionQuality;
int32 MyVar = CVarRefractionQuality.GetValueOnGameThread();

这将返回当前游戏线程上 CVarRefractionQuality 的值。

第二种方法是使用 Getter 函数来获取控制台变量的值,但这种方法较慢。我们可以使用以下代码获取名为 TonemapperType 的控制台变量的值:

static const auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("TonemapperType")); 
int32 Value = CVar->GetInt();

使用这两种方式之一,就可以轻松读取控制台变量的值,并在程序中使用了。

追踪控制台变量修改

部分控制台变量修改需要实时生效,以便我们测试游戏的具体功能。在运行时检测控制台变量的修改是必不可少的:比如,我们修改了一把枪械的攻击力,如果每次都要重新启动游戏测试,那就太繁琐了!

可以通过以下两种方式追踪控制台变量的修改:

  1. 每帧检测控制台变量的值是否发生变化(该方法速度较慢):
// 每帧检测 CVarRefractionQuality 的值是否变化
int32 PreviousValue = CVarRefractionQuality->GetInt();
while (true)
{
    int32 CurrentValue = CVarRefractionQuality->GetInt();
    if (CurrentValue != PreviousValue)
    {
        // 值发生变化,进行相应处理
        // ...
        // 更新 PreviousValue
        PreviousValue = CurrentValue;
    }
    // 其他逻辑处理
}
  1. 注册一个 ConsoleVariableSink,在变量修改后,Sink 绑定的函数会被调用:
// 定义 Sink 回调函数
void MySinkFunction()
{
    // 值发生变化,进行相应处理
}

// 注册 Sink
FAutoConsoleVariableSink CVarRefractionQualitySink(
    FConsoleCommandDelegate::CreateStatic(&MySinkFunction),
    TEXT("r.RefractionQuality")
);

这样,当 r.RefractionQuality 的值发生变化时,MySinkFunction 函数将被调用。

  1. 使用回调函数来检测(但不建议使用这种方法)。
  • 循环可能出现死锁(可以防止死锁出现,但使用哪个回调则不明确);
  • 回调可在 !Set() 被调用中的任意时间处返回。代码必须在所有情况下(在初始化中、在序列化中)均能使用。
CVarResQuality.AsVariable()->SetOnChangedCallback(FConsoleVariableDelegate::CreateStatic(&OnChangeResQuality));

加载控制台变量

有时候,因为某种原因,需要在游戏开始时就将控制台变量设置成某个值。比如,需要关闭一系列影响渲染的参数,方便我们测试单一图像属性引起的性能问题,但我们又不能将默认值覆盖掉,因为它们只是临时的修改。这时,我们便需要提前通过配置文件加载控制台变量。

可以在 Engine/Config/ConsoleVariables.ini 文件中设置控制台变量的默认值。这些默认值可以在游戏启动时通过命令行参数进行覆盖。

[Startup]
FogDensity = 0.9
ImageGrain = 0.5
FreezeAtPosition = 2819.5520 416.2633 75.1500 65378 -25879 0

同时,也可以在 BaseEngine.ini 文件或者游戏项目的 DefaultEngine.ini 文件中设置控制台变量的默认值。比如:

[SystemSettings]
r.MyCvar = 2

[SystemSettingsEditor]
r.MyCvar = 3

还可以通过命令行参数在开启编辑器时设置控制台变量,比如:

UE4Editor.exe GAMENAME -ExecCmds="r.BloomQuality 12,vis 21,Quit"

控制台变量设置的优先级

在 Unreal Engine 中,控制台变量可以在多个地方进行设置,每个设置的优先级是不同的。如果我们通过更高优先级的方式修改了控制台变量,那么较低优先级的改动将不会生效。以下是控制台变量设置的优先级列表,按照从低到高排序:

  • ECVF_SetByConstructor:控制台变量创建时的默认值。
  • ECVF_SetByScalability:在 Scalability.ini 文件中设置的值。
  • ECVF_SetByGameSetting:在游戏 UI 或者来自配置文件中设置的值。
  • ECVF_SetByProjectSetting:在项目设置中设置的值。
  • ECVF_SetByDeviceProfile:在设备文件中设置的值。
  • ECVF_SetBySystemSettingsIni:在 SystemSettings.ini 文件中设置的值。
  • ECVF_SetByConsoleVariablesIni:在 ConsoleVariables.ini 文件中设置的值。
  • ECVF_SetByCommandline:在命令行参数中设置的值。
  • ECVF_SetByCode:在代码中设置的值(通常不建议使用)。
  • ECVF_SetByConsole:在控制台中输入命令设置的值。

可以通过以上列表了解在多个地方设置控制台变量时的优先级关系,从而有效地管理控制台变量。

总结

通过使用控制台变量,我们可以在不重编译游戏的情况下,快速修改一些参数,极大提高开发效率。同时,控制台变量也可以作为游戏调试的重要手段之一,方便我们查看一些关键变量,快速定位问题。

需要注意的是,控制台变量并不适用于所有情况。如果某个变量需要在运行时频繁地修改,或者需要保护变量不被非法修改,那么最好使用其它方式实现。

参考

[1]: 杰森·格雷戈瑞. 游戏引擎架构. 北京: 电子工业出版社. 2019. 
[2]: 虚幻引擎 C++中的控制台变量 | 虚幻引擎 5.1 文档


图片:如无特别说明,文中图片均为作者自制
*本文内容系作者独立观点,不代表 indienova 立场。未经授权允许,请勿转载。

近期点赞的会员

 分享这篇文章

Dluck 

Gamer / Developer 

您可能还会对这些文章感兴趣

参与此文章的讨论

暂无关于此文章的评论。

您需要登录或者注册后才能发表评论

登录/注册