为什么使用UE4提供的容器类?

如果你用过C++的STL库,你就知道STL提供了各种各样的容器/数据结构,使得你对处理很多数据的时候非常快捷高效。UE4同样也提供了类似的库,库里面的类型是以T开头的,使用UE4提供的容器库可以更好地实现跨平台。所以在UE4进行开发的时候我们很少去使用STL容器,更多时候是使用UE4提供的容器。

一、TArray<T>是什么

如果你学过C++的模板,你就知道TArray<T>是一个模板类型,T是由我们指定的任意类型。比如你想创建一个数组元素都是int类型的动态数组,那么这个数组类型就是TArray<int>,类似的,你可以创建TArray<double>、TArray<FString>等等,T甚至是可以是你自己创建的C++类。

TArray<T>中所有数据元素都是T类型的,因此不能混合各种不同类型的元素进去这个容器。TArray没有设计成被继承的,所以不应该去继承它。并且new/delete一个TArray是危险的行为。当TArray的生命周期结束时(超出作用域),容器里面的所有元素也会被销毁。当你从另一个TArray创建一个新的TArray会复制所有数据元素到新的变量,而不会共享这些元素的内存。

二、创建动态数组

为了创建一个动态数组,你可以这样写:

TArray<int32> IntArray;

注意,int32是32位整形,而int会根据机器不同而字节不同,所以为了跨平台建议使用int32。

这时候,因为我们没有数据填充到该数组里面,所以还没有内存被分配。

三、填充动态数组

1) TArray::Init

在UE4的官方文档可以看到该函数的声明:

void Init(const ElementType & Element, int32 Number)

该函数用于设置数组为Number个,并且每个元素值的为Element,例如:

IntArray.Init(10, 5);// IntArray == [10,10,10,10,10]

2) TArray::Add

先来看该函数的声明:

int32 Add( const ElementType & Item)

该函数用于添加新元素到动态数组末尾。

3) TArray::Emplace

先来看该函数的声明:

template<typename... ArgsType>int32 Emplace( ArgsType &&... Args)

该函数也是用于添加新元素到动态数组末尾。示例:

TArray<FString> StrArr;StrArr.Add(TEXT("Hello"));StrArr.Emplace(TEXT("World"));// StrArr == ["Hello","World"]

虽然Add和Emplace都是添加新元素到动态数组末尾,不过它们的内部实现是不同的:

  • Add会复制元素到数组容器里面
  • Emplace使用你给的参数来构造一个新的元素类型的实例

在上面的示例中,Add创建了一个FString临时变量,然后传递给数组,在数组内部再次调用拷贝构造函数来复制这个FString临时变量。但是Emplace使用了C++11的右值引用技术,它不会构造临时变量,而是在数组内部使用这个字符串常量来创建FString变量。因此,由于Emplace少了一次拷贝构造函数操作,所以Emplace会比FString高效。但是由于Add比Emplace更具可读性,如果是普通的C++内置类型(不会有拷贝构造函数的巨大开销),建议使用Add。

4) TArray::Push

TArray::Push提供了两个一样功能的重载函数可以分别代替Add和Emplace。所以无论何时使用Push比Add和Emplace更加方便了:

void Push( const ElementType & Item )void Push( ElementType && Item )

四、迭代动态数组

通常迭代都至少有两种方式,一种是使用索引,一种是使用迭代器。

1) 使用索引迭代动态数组

为了练习我们的数组,我们可以在靠近NPC的函数中打印该数组。我们将ANPC::Prox_Implementation修改成如下代码:

  1. void ANPC::Prox_Implementation(
  2. AActor* otherActor,
  3. UPrimitiveComponent* otherComp,
  4. int32 otherBodyIndex,
  5. bool bFromSweep,
  6. const FHitResult & sweepResult
  7. ){
  8. //通过强制转换成AAVatar是否成功来判断是否玩家角色
  9. if (Cast<AAvatar>(otherActor) == nullptr)
  10. {
  11. return;
  12. }
  13. //获得第一人称控制器
  14. APlayerController* PController = GetWorld()->GetFirstPlayerController();
  15. if (PController)
  16. {
  17. //获得HUD界面
  18. AMyHUD* hud = Cast<AMyHUD>(PController->GetHUD());
  19. hud->AddMessage(Message(NpcMessage, 5.f, FColor::White));
  20. //测试数组
  21. TArray<int> array;
  22. array.Push(1);
  23. array.Push(3);
  24. array.Push(7);
  25. for (int index = 0; index < array.Num(); index++)
  26. {
  27. //GEngine是全局引擎变量,我们使用它的AddOnScreenDebugMessage函数来在游戏屏幕上打印调试信息。
  28. //该函数第一个参数是调试输出的位置,填写-1表示总在原来的调试信息上方。
  29. //第二个参数是字体大小,第三个参数是字体颜色,第四个参数是要打印的字符串,这里用FromInt函数将Int转换FString。
  30. GEngine->AddOnScreenDebugMessage(-1, 40, FColor::White, FString::FromInt(array[index]));
  31. }
  32. }
  33. }


注意,每次调试打印的信息都在原来的调试信息上面,所以数组里面的内容依次是1、3、7,而不是7、3、1。

2) 使用迭代器循环数组

  1. void ANPC::Prox_Implementation(
  2. AActor* otherActor,
  3. UPrimitiveComponent* otherComp,
  4. int32 otherBodyIndex,
  5. bool bFromSweep,
  6. const FHitResult & sweepResult
  7. ){
  8. //通过强制转换成AAVatar是否成功来判断是否玩家角色
  9. if (Cast<AAvatar>(otherActor) == nullptr){
  10. return;
  11. }
  12. //获得第一人称控制器
  13. APlayerController* PController = GetWorld()->GetFirstPlayerController();
  14. if (PController)
  15. {
  16. //获得HUD界面
  17. AMyHUD* hud = Cast<AMyHUD>(PController->GetHUD());
  18. hud->AddMessage(Message(NpcMessage, 5.f, FColor::White));
  19. //测试数组
  20. TArray<int> array;
  21. array.Push(1);
  22. array.Push(3);
  23. array.Push(7);
  24. //在使用容器的时候,为了容器的操作一致性,通常都会像下面这样使用迭代器来循环
  25. //所谓的迭代器其实类似于一个指针,当对指针进行++时,就指向后面的元素。
  26. //当超出容器范围的时候,迭代器为空,跳出循环
  27. for (TArray<int>::TIterator it = array.CreateIterator(); it; ++it)
  28. {
  29. //GEngine是全局引擎变量,我们使用它的AddOnScreenDebugMessage函数来在游戏屏幕上打印调试信息。
  30. //该函数第一个参数是调试输出的位置,填写-1就不会覆盖以前的调试信息。
  31. //第二个参数是字体大小,第三个参数是字体颜色,第四个参数是要打印的字符串,这里用FromInt函数将Int转换FString。
  32. GEngine->AddOnScreenDebugMessage(-1, 40, FColor::White, FString::FromInt(*it));
  33. }
  34. }
  35. }

在实际开发中,因为使用迭代器进行迭代更简洁美观,我们通常都会这样进行迭代容器。


转自:http://www.52vr.com/article-566-1.html

[unreal4入门系列之十五] UE4中的动态数组:TArray容器相关推荐

  1. [unreal4入门系列之十六] UE4中的集合:TSet容器

    一.TSet<T>是什么 UE4中,除了TArray动态数组外,还提供了各种各样的模板容器.这一节,我们就介绍集合容器--TSet<T>.类似于TArray<T>, ...

  2. [unreal4入门系列之十一] 在UE4中编写C++代码控制角色

    当你运行我们上次做完的项目,你可能会意识到我们移动的摄像机还是默认的那个摄像机,这个默认的摄像机可以自由飞翔.这一节,我们要使得开始的角色是我们的一个Avatar类的实例对象,并且使用键盘控制我们的角 ...

  3. Reflex WMS入门系列二十五:将叉车纳入系统进行管理

    Reflex WMS入门系列二十五:将叉车纳入系统进行管理 据笔者所知,SAP WM 模块里是不对仓库里常用的叉车等仓库管理工具进行管理的.笔者发现,Reflex WMS系统则会在很多仓库部门日常操作 ...

  4. [unreal4入门系列之十四] 在UE4中添加碰撞触发事件

    一.在HUD中显示消息 1) 在MyHUD.h中定义一个结构来表示我们的消息: #pragma once #include "GameFramework/HUD.h" #inclu ...

  5. [unreal4入门系列之十二] 在UE4中创建非玩家角色(NPC)

    现在我们来创建一些NPC(non-playable characters,非玩家角色).在这个游戏中,当我们靠近NPC时,它们会做出相应的反应. 创建C++类 1) 在UE编辑器中,打开文件-新建C+ ...

  6. [unreal4入门系列之十] UE4添加角色到场景中

    现在我们已经有了一个场景并且运行了,我们需要添加一个角色到场景中.要这样做,我们必须从UE4的GameFramework类继承它. 一. 打开上次创建的关卡 如果你已经关闭了项目,并且保存了上次创建的 ...

  7. Pr入门系列之十五:校色与调色

    Pr 传统调色控件主要在效果面板里的"颜色校正"组中. "图像控制"组与"过时"组里也有一些调色校色工具. 有关上述调色控件的说明请参阅&l ...

  8. 【ASE入门学习】ASE入门系列二十五——努努冰球材质复刻

    共由5个部分组成 Wenli模型的图不好,需要你自己换成冰的贴图,大致调成如上结果即可,暗部分可以根据个人喜好调吧,视频是用粒子发射器的,我直接模型(5个物体)做Animation旋转.

  9. Go入门系列(十八) 反射、包和测试工具

    本系列文章目录 展开/收起 Go入门系列(一) 初识Go语言 Go入门系列(二) 变量.指针.数据类型简介和作用域 Go入门系列(三) 基础类型--整型.浮点型.布尔类型和字符串 Go入门系列(四) ...

最新文章

  1. Java核心类库-IO-字节数组流/内存流
  2. python读取用空格分隔的文字_Python:从类似readlin的文件中读取空格分隔的字符串...
  3. 数据仓库之 ETL漫谈
  4. MoveAbsJ在使用时和MOVEJ有什么区别
  5. Android项目实战欢迎界面
  6. 一文读懂架构整洁之道(附知识脉络图)
  7. gcc之UTF-8编码
  8. android4.2 高用zing拍照后,返回其它页面操作时,主线程关掉或程序退出的问题解决...
  9. 数据结构与算法之-----栈的应用(三)
  10. opencv 骨架提取_抗爆墙方盛提取车间抗爆墙记录@温州贴吧
  11. 期待人工智能在合作时的表现
  12. 【Docker】总集篇
  13. java 解析ttf字体文件_stb_truetype解析ttf字体并将其保存到图片中
  14. U-boot下编写代码对SPI flash进行操作
  15. RK3288 android添加HAL 层导致无法进入主界面原因分析,重复打印 camsys_marvin(deaa1510) is closed
  16. 【福利】免费领取企业信息查询两年VIP会员
  17. Cadedce Allegro 里面怎么切线删除一条线上的某一段
  18. 88是python的整数类型吗_python基本数据类型
  19. 如何为超级通胀做好准备
  20. 公司-便利蜂:便利蜂

热门文章

  1. 微信扫码支付模式二【无法回调】解决方案
  2. 异常检测算法--Isolation Forest
  3. Eslint报错整理与解决方法(持续整理)
  4. 如何在Mac上的IntelliJ IDEA中增加IDE内存限制?
  5. 基于容器宽度的字体缩放
  6. MySQL中INDEX,PRIMARY,UNIQUE,FULLTEXT之间的区别?
  7. python 学习笔记 12 -- 写一个脚本获取城市天气信息
  8. 如何基于MySQL及Redis搭建统一的kv存储服务 | 秦波
  9. CentOs6.5中安装和配置vsftp简明教程
  10. 简单验证码识别 tessnet2