3 - UE代码规范

腾讯2024游戏客户端公开课笔记,UE的C++代码规范部分,这节课的目标是:

  • 了解通用代码规范;
  • 了解UE5中C++代码规范
  • 了解UE5中的标识符

通用代码规范

代码规范就是编写某语言的一系列指导方针,包括代码风格、缩进、注释、命名等方面,通常由团队/组织/公司制定。

代码需要长期维护,且一份代码可能会被多个人所查看与编辑。一致的代码规范可以提高代码的可维护性,可读性。从而在一定程度上增加开发效率。

常见的代码规范有谷歌的、腾讯的等,可以通过.clang-format工具来帮忙一键格式化代码。

UE5的C++代码规范

有人说UE5使用的是U++,而不是C++,这是因为它自己实现了更高效的标准库,要想编程得用它提供的容器。UE5也有自己的一套代码规范,可在这里查看。常用的代码规范如下:

命名

变量命名要求清晰、明确且避免过度缩写。此外还要遵循大驼峰式命名(CamelCase),bool类型需要加b前缀。遵循大驼峰式命名的原因是,UE5会将一些变量名反射到编辑器中,大驼峰变量名会被自动分词。例如TestCase会变成Test Case

UE5对类的命名也有严格的命名规范,如果不遵循可能会出现编译错误:

开头字母含义示例
T模板类TMap
U继承自UObject的类UMoviePlayerSettings
A继承自AActor的类APlayerCameraManager
S继承自SWidget的类SCompoundWidget
I抽象接口类INavNodeInterface
E枚举类EAccountType
F其他类FVector

数据类型

UE5中常见的数据类型如下:

数据类型意义大小(字节)
bool布尔值sizeof(bool)
TCHAR字符sizeof(TCHAR)
int8/uint8有符号/无符号字节1
int16/uint16有符号/无符号短整数2
int32/uint32有符号/无符号整数4
int64/uint64有符号/无符号长整数8
float单精度浮点数4
double双精度浮点数8
PTRINT与指针同样大小的整数sizeof(PTRINT)

如果要在UE5中使用字符串,需要用UE定义的一些容器,如FString/FText/FName/TCHAR等。如果要在UE5中使用容器,应该避免使用C++提供的STL库,而是使用它自定义的TArray/TMap等,这是因为容器的内存分配必须受到引擎的控制。

此外,在UE中类的代码中可能会发现如下情况:

UPROPERTY()
uint8 bXXXX:1;

这句代码的意思是只用一个bit存储该变量,以节省空间。

命名空间

在命名空间方面,需要注意以下几点:

  • UnrealHeaderTool仅支持全局命名空间的类型;
  • 不要在全局命名空间使用using声明;
  • 一些宏在命名空间内可能会失效,可以尝试UE_xxx。

UE5中的标识符

UE5中可以通过一些标识符来对变量、类、函数等做一些约束。标识符的通用结构如下图所示:

img

原理

编写好一个文件后,UHT会将头文件通过反射生成xxx.generated.h/cpp,最后会让UBT编译。

UPROPERTY

这种标识符会将被标注的成员反射到编辑器中,并且根据限定符的不同,反射的结果也有所不同。例如有一个结构体FCat,并声明了两个FCat变量:

UPROPERTY(EditAnyWhere, Category="111")
FCat Cat1;

UPROPERTY(EditAnyWhere, Category="222", meta=(ShowOnlyInnerProperties))
FCat Cat2;

那么它们在编辑器中反射的结果如下:

// 第一个
111
    Cat1
    	xxx
    	xxx

// 第二个
222
    xxx
    xxx

常用限定符的解释如下:

  • VisibleAnywhere:在编辑器中只读;

  • EditAnyWhere:支持在编辑器内编辑;

  • BlueprintReadOnly:蓝图中只读;

  • BlueprintReadWrite:蓝图中读写;

  • Category:分类,是编辑器中展开收起的标签名。

    例如:

    UPROPERTY(EditAnyWhere, Category="Animals")
    bool bIsCute;
    
    UPROPERTY(EditAnyWhere, Category="Animals|Dogs")
    FString BarkWord;
    
    UPROPERTY(EditAnyWhere, Category="Animals|Birds")
    int32 FlyingSpeed;

    它们在编辑器中反射的结果如下:

    Animals
        Is Cute
        Dogs
        	Bark Word
        Birds
        	Flying Speed
  • AdvancedDisplay:对于一些低频修改的属性,或者是只针对进阶者使用的属性,可以使用此项标注。这样在编辑器中需要展开才能看到此项。

  • meta:属性的元信息,用来辅助反射系统。例如:

    • ShowOnlyInnerProperties可以忽略变量名;
    • DisplayName可以自定义在编辑器中展示的命名;
    • DisplayPriority可以决定该属性显示的优先级;
    • ClampMin, ClampMax可以决定该属性的范围;

UFUNCTION

专门给函数使用的标识符,它的常用限定符如下:

  • BlueprintCallable:支持在蓝图中使用;
  • Category:在蓝图中被反射到的类别;
  • meta:可以通过meta = (Xxx = "xxx")来给函数任意位置的参数赋默认值,只在蓝图节点中有效。

UCLASS

专门给类使用的标识符,需要将#include "Xxx.generated.h"放在包含列表的最后。并且在类中需要添加GENERATED_BODY()宏。

它的常用限定符如下:

  • BlueprintTypeBlueprintable:方便在蓝图中访问;
  • config=Xxx:应用XXX的设置;
  • metaShortToolTip可以设置在蓝图中的简短提示;

USTRUCT

专门给结构体使用的标识符,需要在结构体中添加GENERATED_USTRUCT_BODY()宏。

UENUM

专门给枚举类使用的标识符。

拓展阅读

  1. UE5官方文档:虚幻引擎元数据说明符
  2. UE5标识符详解 | 史上最全 - 知乎 (zhihu.com)