1. Overview
本教程旨在讲解在虚幻引擎(UE4) c++中实现蓝图(Blueprint)可调用的任意类型数组排序的蓝图节点。纯蓝图实现任意类型数组排序方法,请查看第1期 在蓝图实现任意类型数组排序。特别声明,本篇文章主要代码来源于网络,本人仅做综述性整理与回顾(review), 如有侵权,请联系删除。编者水平有限,如有错漏敬请谅解。
2. Introduction
排序算法是开发过程中常用的一类算法,使用ue4进行开发不可避免的要用到排序算法。若仅使用ue4 c++进行内容开发,可以直接调用c++ stl中的排序算法,就可以实现数组排序。由于ue4 c++本身并没给蓝图系统(Blueprint System)提供任意类型数组排序的节点,因此当同时使用ue4 c++和Blueprint(BP)完成逻辑功能,如何在ue4 c++ 中实现一个任意类型数组排序蓝图节点,就成为一个值得深究的问题。
本文主要讲解ue4 c++实现任意类型数组排序的蓝图节点方法和原理,以及该节点在Blueprint中的使用方法。
3. Required Knowledge
1.熟悉ue4 c++的语法规则
2.了解ue4 反射机制和使用方式;
4. Why
Blueprint中常使用的类型,除基本类型(int/float/sting/vecto/transform…)外,其他最为常用的大类是UStruct类 和UObject派生类。这二大类伴随整个开发过程,并且随时会增加新的UStruct类型和UObject派生类。
如前所述,当开发人员同时使用ue4 c++和Blueprint进行开发时,开发人员无法预知将要用到的所有类型对象(UClass/UStruct),难以给每一种需要进行排序的类型定义排序方法来,并暴露给Blueprint;主要原因是blueprint不支持C++的模板,无法直接将一个C++模板函数暴露给蓝图。但是Blueprint支持Wildcard(通配符)类型参数,举例来说Blueprint System中Utilities|Array目录下的蓝图节点都是通配符类型的蓝图节点,对于任意类型数组都可以使用同一个蓝图节点实现该数组的Add/Clear/Find的方法。因此 在ue4 c++实现接收任意数组类型的蓝图节点 (Blueprint Node)是理论可行的。
5. Sort Approach
下面介绍在ue4 c++中实现排序的蓝图节点实现方法。排序的关键在于如何比较二个数组成员的大小,对于任意类型数组,由于在未连接该蓝图节点之前,并不知道该数组成员比较大小的方法,因此实现任意类型数组排序的蓝图节点,不仅要知道数组还需要知道大小比较的方法。通常要知道二个数组成员的大小比较结果有二种方式:
其一:基于FindFunction方法,ue4 UObject支持根据名称(FunctionName)查找的函数,并且可以在不知道该函数具体实现的时候直接调用。因此在排序节点上传入一个函数名FunctionName,在c++中需要比较二个成员大小时,直接调用该比较函数进行大小比较,并将结果作为二个数组成员的大小比较结果。
其二,基于FindField方法,由于ue4 UStrcut/UObject均支持属性(UProperty)的查找和遍历,因此可以通过传入一个PropertyName查找该数组成员的UPropery以及对应的Value值,使用该Value值来进行大小比较,并将比较结果作为二个数组成员的比较结果。
5.1 基于stl库非通用蓝图排序节点
创建以Blueprint Function Library为基类c++类,在该类的头文件(.h文件)中定义待排序的结构体类型 (本例为FSortStruct),并在头文件中声明排序函数,示例如下
UFUNCTION
在源文件(.cpp)实现该排序方法
void
编译完成后,可以在蓝图中找到该节点
![47e680597a3e02b4cb4b4dd4b695d130.png](https://i-blog.csdnimg.cn/blog_migrate/b8918423a393541cda4e49c7841775c3.png)
点评
优点:实现方法简单,本质上是调用stl库中的排序算法,因此算法效率高,这也是实现蓝图排序节点最为常用的一种方法。
缺点:不支持通配符类型数组,无法重用。
5.2 基于FindFunction方法实现通用蓝图排序节点的方法
该方法来源于 邱子鉴,西山居技术中心,地址:http://tech.seasungame.com/blog/index.php/2017/08/14/ue4-zailantuzhongshixianshuzupaixugongneng/
源代码:
UFUNCTION
使用方法示例:
![e999c3f02ca2b8708929a20e4134873c.png](https://i-blog.csdnimg.cn/blog_migrate/165183a167ac300f9af96071a4b2ac4a.jpeg)
![3ebb4277f04582689b1bf4c727ca089d.png](https://i-blog.csdnimg.cn/blog_migrate/a00b998681df45a3cb21d0c799b1bc24.jpeg)
![9690a44c36716fe5899695dd0f9e6fc0.png](https://i-blog.csdnimg.cn/blog_migrate/50c47f55035b5bc53d16e864efa3ff4b.jpeg)
点评:
优点:支持任意类型数组排序,如(UObject、UStruct以及基本类型(int, float…)),自定义排序数组成员比较方法,大大扩展了该排序节点的使用场景,如当第一个变量相等时,比较第二个变量的情况。
缺点:该方法基于冒泡排序方法,冒泡排序时间复杂度最坏的情况是O(n^2),效率较低。
5.3 基于FindField方法实现通用蓝图排序节点的方法
该方法来源于 https://github.com/EverNewJoy/VictoryPlugin,VictoryBPFunctionLibrary::Array_Sort()
// .h file
/**
// .cpp file
//Reference: https://github.com/EverNewJoy/VictoryPlugin
特别提醒:上述代码在原始代码的基础上添加一个函数Algorithm::FindField(),用于支持蓝图结构体(在蓝图中定义的结构体)数组排序时,无法查找到UProperty问题。
修改的位置:
UProperty
使用方法示例:
![bec429842d9225c104b7fd24b20e50d8.png](https://i-blog.csdnimg.cn/blog_migrate/a0001d4077df5b81e6b839e2d0b8a7d7.jpeg)
结果输出:
![39ea0d3f0e677256ceb64ec437b67c46.png](https://i-blog.csdnimg.cn/blog_migrate/af9b0555f65856466df8bc39828b6301.jpeg)
点评
优点:支持任意类型UStruct和UObject子类数组的排序。
缺点: 仅支持一个变量参数的比较,不支持基本类型数组排序。该方法仍然是基于冒泡排序算法,效率低于stl排序算法。
6. Conclusion
本文主要介绍了二种 ue4 c++实现任意类型数组排序蓝图节点的方法,用于满足日常开发的蓝图排序需求。由于二者均为冒泡排序原理,算法效率一般低于的stl排序算法。
进阶版:基于stl排序算法的任意类型数组排序节点的实现,待完成。