大家好,欢迎来到《分享本周所学》第九期。本人是一名人工智能初学者(虽然我最近写的东西都跟人工智能没什么关系),刚刚大一。我之前是有C++算法基础和UE4纯蓝图游戏开发基础,但是在尝试用C++开发UE的时候,感觉和这两者都有很大区别。我在学习的过程中也遇到了比较多的稀奇古怪的问题,所以想给大家分享一下这个过程,希望可以帮到大家。

        这篇文章主要是针对C++在UE5中的特定用法和UE5对C++作出的限制,而不是关于C++本身。这篇文章面向我这种能够理解C++的基础语法但刚刚接触UE5的新手。

目录

一、命名规则

1. 类名

2. 变量名

二、构造类的对象


上期文章链接:

分享本周所学——Unreal Engine 5(UE5/虚幻引擎5)安装以及创建项目的常见问题icon-default.png?t=N4P3https://blog.csdn.net/weixin_48978134/article/details/130798350

本期封面又懒得搞了,主要是这两期内容都想不太到什么好的戴佳伟笑话。


一、命名规则

        在UE5中,给C++的类和变量命名是很有讲究的,讲究的就是一个不知道为什么要这么讲究。

1. 类名

        UE5重新定义了C++中的整型。比如对于最基本的整形int,UE5中自己定义了一个叫int32的变量类型来代替它。这样做的目的是避免C++原本的int类型在不同的平台和编译器上可能会有不同的位数,而UE5的int32强制整型变量在所有平台上的长度都是32位,这样可以方便跨平台开发。C++原本的int也是可以用的,不会导致编译错误,但是建议还是用int32。我刚刚开始写代码的时候就是不知道int要用int32代替,然后有一次找ChatGPT生成代码,结果它生成的代码里边所有的int都用int32,我一查才直到还有这么个讲究。

        除了int32之外,还有int8、int16、int64,分别对应不同长度的整型,可以用来代替short或者long long之类的类型。如果想要表示无符号整型,可以在变量类型前面加上“u”,比如uint8、uint32。

        但是不知道为什么,UE5没有定义自己的浮点型变量,所以我们如果想使用浮点型变量的话,还是用C++原本的float或者double。在UE5中,一般能用float的地方就不用double。

        值得一提的是,UE5中有时会使用uint8来代替bool表示布尔型变量。这是因为UE5对于布尔型有自己的优化方式,比如可以把同一个类中的多个布尔型成员变量存在同一个uint8变量中来节省内存空间。一般来讲,在定义布尔型函数、函数的参数和局部变量时,使用bool代表布尔型,而在定义类的布尔型成员变量时会使用uint8。
        除了这些基本类型,UE5对于一些其他的类型和我们自己定义的类也有相应的命名规则,比如说所有结构体的名字都以F开头。UE5自带的一些常见的结构体有FString(字符串)、FVector(三维向量)、FVector2D(二维向量)等等。模板类一般以T开头,UE5自带的模板类有TArray(数组)、TMap(用来代替std::map)、TSet(用来代替std::set)等等。另外,所有接口需要以I开头、所有继承自UObject的类需要以U开头,其中所有继承自AActor的类要以A开头。总之就是如果你自己定义了一个类或者结构体,你可能需要花点时间来搞清楚类名应该用什么字母开头。不过类名的开头字母也不是强制性要求,如果你不按照这个命名规则来也不是不行。这个命名规则只起到增加代码可读性和可维护性的作用。

2. 变量名

        UE5中,定义的变量(至少是蓝图中可见的变量)中所有单词需要首字母大写,比如我想定义一个int32型的变量:

int32 MyInt; // 不是myInt或者my_int。

        这可能有一点反直觉,因为我感觉一般我们不管用什么语言开发,使用的一般变量的变量名首字母都是小写的,然后分隔单词用下划线或者驼峰命名,但是UE5中通常使用这种所有单词首字母大写的方式。另外,所有布尔型的变量前面需要加上小写字母“b”,比如:

uint8 bMyBool;

        或者:

bool bMyBool;

        不过这也只是一种约定俗成的命名规则,并不是强制的要求。

        在变量被放进蓝图的时候,UE5会贴心地在每个单词之间加一个空格,使变量看起来更加美观。另外,如果你的变量名没有首字母大写,UE5会自动把首字母变成大写。如果变量名中有下划线,下划线也会被转换成空格。所以,如果有一个整型变量InputVal,不管你写成inputVal或者input_val,在蓝图中都会显示为:

        所以UE5这种另辟蹊径的命名方式似乎也没有什么卵用。顺便一提,在布尔型变量前加的小写字母“b”,还有类名前面的“U”、“F”、“I”等字母都不会显示在蓝图里。

二、构造类的对象

        在C++中,我们在构造类的一个对象的时候通常使用构造函数,但是在UE5中不行。或者说,我们不能使用有参数的构造函数来初始化一个对象。在UE5中,我们如果想创建一个对象要么通过蓝图、要么通过C++。如果是用蓝图的话,可以用SpawnActorFromClass来生成一个对象:

        这个节点有三个参数:Class表示我们创建哪个类的对象;SpawnTransform包含了对象的位置、旋转和尺寸信息;CollisionHandlingOverride用来处理生成对象时的碰撞问题。显然啊,我们在调用这个节点的时候时没有办法给构造函数传参数。

        如果使用C++的话,可以使用NewObject或者SpawnActor。NewObject适用于生成一些不需要显示在场景中的内容。假设我们要生成一个UMyClass类的对象,可以使用如下代码:

UMyClass* MyInstance = NewObject<MyClass>();

        而SpawnActor适用于需要展示在场景中的内容。SpawnActor是AActor类的成员函数,所以只能在AActor类中使用,而且只能生成AActor的子类。如果我们要生成一个AMyActor类的对象,可以使用如下代码:

AMyActor* MyInstance = GetWorld()->SpawnActor<AMyActor>();

        但是显然,不管使用哪个,都没有办法给构造函数传参数。那我们要怎么初始化一个对象呢?其实很简单,我们可以在类里定义一个用来初始化的函数(但不是构造函数),然后在创建对象之后把需要初始化的内容作为参数传进这个函数。如果你执意使用带参数的构造函数的话,可能导致引擎报错或者崩溃。

        这个创建对象的问题真的是困扰了我非常长时间。之前写好了一段代码想着测试一下,结果每次测试引擎都莫名其妙崩溃。然后我靠注释代码把问题锁定在一个构造函数上,我一开始以为是构造函数里的哪句代码出问题了,结果我把构造函数里所有代码都注释掉了问题还是没解决,引擎还是崩溃。最后才意识到问题是出在了构造函数本身,带参数的构造函数本来就不应该存在。

        你可能注意到,我在创建对象的时候使用的变量类型都是指针,这是因为UE5中绝大多数情况都只支持用指针储存对象。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐