首页 > 技术文章 > Aery的UE4 C++游戏开发之旅(2)编码规范

KillerAery 2019-12-12 12:17 原文

C++基础类型规范


由于PC、XBOX、PS4等各平台的C++基础类型大小可能不同(实际上绝大部分都是整型类型的大小不同),因此UE4提供了如下可移植基础类型的别名来统一规范类型大小:

  • bool 代表布尔值(不会假定布尔尺寸)
  • TCHAR 代表字符(不会假定TCHAR尺寸)
  • uint8 代表无符号字节(1字节)
  • int8 代表带符号字节(1字节)
  • uint16 代表无符号“短”字符(2字节)
  • int16 代表带符号“短”字符(2字节)
  • uint32 代表无符号整数(4字节)
  • int32 代表带符号整数(4字节)
  • uint64 代表无符号“四字”(8字节)
  • int64 代表带符号“四字”(8字节)
  • float 代表单精确浮点(4字节)
  • double 代表双精确浮点(8字节)
  • PTRINT 代表可能含有指针的整数(不会假定PTRINT尺寸)

修正:应当在所有地方使用UE4提供的可移植类型,这在需要明确基础类型尺寸大小(例如需要序列化等功能)的情形提供良好的移植特性,应当成为一种习惯以避免以后一些不必要且难以察觉的跨平台类型bug

C++类、结构体、枚举规范


类 class

一般用UE4编辑器来创建C++类即可填补类所需要的宏,也就自动遵守了规范,无需说明。

结构体 struct

  1. 在UE4编辑器新建一个空类(None),顺便注意下结构体的命名规范
  2. 删掉里面类的内容,换成结构体的内容
#pragma once
#include "CoreMinimal.h"
#include "FMyStruct.generated.h"

USTRUCT(BlueprintType)	//蓝图亦可访问该结构体类型
strcut FMyStruct
{
	GENERATED_USTRUCT_BODY()

	//示例
	URPOPERTY(EditAnywhere,BlueprintReadWrite)	//将字段公开给蓝图访问
	float Value;
};

枚举 enum

  1. 在UE4编辑器新建一个空类(None),顺便注意下枚举的命名规范
  2. 删掉里面类的内容,换成枚举的内容
#pragma once
#include "EMyEnum.generated.h"

UENUM(BlueprintType)	//蓝图亦可访问该枚举类型
enum class EMyEnum : uint8
{
	//示例
    Value0 UMETA(DisplayName = "枚举值0"),
    Value1 UMETA(DisplayName = "枚举值1"),
    Value2 UMETA(DisplayName = "枚举值2")
};

命名规范


  1. 命名(如类型或变量)中的每个单词需大写首字母,单词间通常无下划线

    例如:Health 和 UPrimitiveComponent,而非 lastMouseCoordinates 或 delta_coordinates

  2. bool变量必须以b为前缀(例如 bPendingDestruction 或 bHasFadedIn)

  3. 类型名前缀需使用额外的大写字母,用于区分类型名和变量名

    例如:FSkin 为类型名,而 Skin 则是 FSkin 的实例

    类型命名前缀规范如下:

    类别 前缀
    继承自 UObject U
    继承自 AActor A
    继承自 SWidget S
    抽象界面类的前缀 I
    结构体类的前缀 F
    枚举类的前缀 E
    模板类 T
    其它多数类 F

    部分子系统则以其他字母为前缀

    模板实例化的Typedef不再是模板,并应加上相应前缀,例如:typedef TArray<FMytype> FArrayOfMyTypes;

  4. 蓝图命名:"BP"+类别缩写+"_"+名字

    例如: BPA_Player

    蓝图类别 前缀
    蓝图Actor BPA_
    蓝图结构 BPS_
    蓝图枚举 BPE_
    蓝图接口 BPI_
    蓝图函数库 BFL_
    蓝图宏库 BML_

头文件包含规范


  • 确保自己include的头文件不要放在 "XXX.generated.h" 文件下面,因为Unreal Header Tool编译工具默认这个文件就是头文件列表的最后一行了

源码文件规范


  • 应将C++代码文件都保存为utf8格式:否则可能会出现在UE4蓝图中调用C++代码(函数、类等)时,出现注释乱码的情况
  • 在文件结尾留一行空行:所有的.cpp和.h文件都应该留一行空行以便于更好的兼容gcc编译器

命名空间规范

  • 不要在全局作用域内使用“using"声明,甚至包括在. cpp文件内也是如此;只可以在一个命名空间内或函数体内使用“using”声明命名空间

这里仅限定当using关键字作为命名空间语法使用时,其余用法不在此建议内(如定义模板别名时)

// Example
void FBlueprintNativeCodeGenManifest::InitDestPaths(const FString& PluginPath)
{
	using namespace BlueprintNativeCodeGenManifestImpl;
    //....
}
  • 前置声明的类型要在各自的命名空间中声明,否则会出现链接错误

字符串规范


  • 在字符串字面量周围使用 TEXT() 宏:若未使用,构建 FStrings 的代码将导致不理想的字符转换过程
"Hello World!";			//Not so well
TEXT("Hello World!");	//OK
  • TCHAR字符串与char/wchar_t字符串的相互转换要使用到UE4提供的转换宏,但是使用转换宏时要注意:只在给函数传参时使用这个宏转换,千万不要保留指向它们的指针
SomeAPI(TCHAR_TO_ANSI(TcharString));                    // OK
const char* SomePointer = TCHAR_TO_ANSI(TcharString);   // Bad!!!

有关这两点规范更详细的解释可以看 Aery的UE4 C++游戏开发之旅(5)字符&字符串

错误处理规范


  • 不要使用C++异常机制(try,catch),UE4代码默认是不支持的,推荐使用Assertions
//example
int i=1;
verify(i==0);

具体UE4提供的断言可查看:虚幻引擎4 官方文档 | 断言相关规范

注释规范


JavaDoc 规则

UE4支持基于JavaDoc规则自动从代码中提取注释并生成文档,所以注释可以采用JavaDoc形式

/**
* Check against another vector for equality, within specified error limits.
*
* @param V The vector to check against.
* @param Tolerance Error tolerance.
* @return true if the vectors are equal within tolerance limits, false otherwise.
*/
bool Equals(const FVector& V, float Tolerance=KINDA_SMALL_NUMBER) const;

对于简单的函数或方法,把参数说明放到函数的描述性注释中也是可以的

/**Create a copy of this vector, with its magnitude clamped between Min and Max.*/
FVector GetClampedToSize(float Min,float Max) const;

JavaDoc 注释规范可看参考链接。

使用第三方库 & 修改UE4引擎源码

引擎中包含的所有第三方代码都应该使用容易搜索的注释标签

// @third party code - BEGIN Physx
#include <physx.h>
// @third party code - END Physx
// @third party code - BEGIN MSDN SetThreadName
// [http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx]
// Used to set the thread name in the debugger
...
// @third party code - END MSDN SetThreadName

当需要修改引擎中所使用的某个库的代码时,需要确保在修改处增加//@UE4注释标记,同时要加上修改原因。这样会使在合并该库的新版本时更加容易,而且也可以让授权方很容易找到所有修改

//@third party code BEGIN SIMPLXGON
/** Get the Hash for the file being imported,Provides enormous speed jimpouements for large CA0 file imports */
static FMD5Hash GetFileHash()
{
	return FileHash;
}
//@third party code ENDSIMPLYGON

参考


系列其他文章:Aery的UE4 C++开发之旅系列文章

推荐阅读