.vs VS环境配置文件(不用管不要删)
Binaries 存放编译生成的结果二进制文件。该目录可以gitignore(可以忽略),每次都会生成
编译动态库 中间编译文件(虚幻按模块编译)(编译好的)
每个模块会产出一个动态库
当工程出了一些问题(热加载出问题),就把动态库全删掉重新生成
config 配置文件
content 内容文件夹,所有资源和蓝图等都在该目录里
intermediate 中间文件(gitignore),存放着一些临时生成的文件,有:
1.build的中间文件,.obj和预编译头等
2.UHT预处理生成的.generated.h/.cpp文件
3.VS.vcxproj项目文件,可通过.uproject文件生成编译生成的shader文件夹
4.AssetRegistryCache:Asset Registry系统的缓存文件
(Asset Registry可以简单理解为一个索引了所有uasset资源头信息的注册表)
(CachedAssetRegistry.bin文件也是如此)
saved 存储自动保存文件,其他配置文件,日志文件,引擎崩溃日志,硬件信息,烘培信息数据等。gitignore
source 源码文件夹(工程源码)
.sln VS启动文件
.uprojece
.VC.db
1.Engine引擎源码文件(只读)(不完整),虚幻是开源项目我们可以直接在工程中看到引擎源码但是无法修改。如需修改需下载Git源码工程
2.Games项目工程文件(主要编写逻辑文件),我们的代码需要在此工程中编写。虚幻中采用了编译模块方式进行引擎构建,所以对于引擎来说,我们编写的内容只是一个模块,模块会被动态编译成库文件,加载到引擎中使用。Target.cs就是模块配置文件
3.Visualizers虚幻4.21加入的文件夹,VS编辑器配置文件
状态 | engine | game | 其他 |
debug(调试)(可查看信息更多,牺牲一些CPU和GPU事件来收集信息) | debug |
debug | 必须在编译器上加-debug参数才能反射查看代码更改 |
debuggame(调试游戏) | release | debug | 适合只调试游戏代码 |
development(开发)(一般用这个) | release | release | 允许编辑器发射查看代码更改 |
shipping(发行)(性能最优) | release | release | 无控制台命令,统计数据和性能分析 |
test(测试) | release | release | 启用了一些控制台命令,统计数据和性能分析 |
目标 | |
空白 | 不带编辑器的一个独立可执行版本,需要提前打包烘培内容资源 |
editor(编辑器) | 直接在编辑器里打开游戏项目 |
client(客户端) | 多人联机项目,生成客户端版本,需要提供 |
server(服务器) | 多人联机项目,生成服务器版本,需要提供 |
变量命名规则
1.模板类以T作为前缀,比如TArray,TMap,TSet
2.UObject派生类都以U前缀
3.AActor派生类都以A前缀
4.SWidget派生类都以S前缀(组件)
5.全局对象使用G开头,如GEngine
6.抽象接口以I前缀
7.枚举以E开头,结构体都是以ST开头
8.bool变量以b前缀,如bPendingDestruction
9.其他的大部分以F开头,如FString,FName
10.typedef的以原型名前缀为准,如typedef TArray FArrayofMyTypes;
11.在编辑器里和C#里,类型名是去掉前缀过的
12.UHT在工作的时候需要你提供正确的前缀,所以虽然说是约定,但你也得必须遵守(编译系统怎么用到那些前缀,后续再讨论)
UE遵循帕斯卡命名法则
虚幻里没有多继承,有接口
资源命名规则
类型 | 前缀 | 说明 |
Level/Map | L_ | 关卡 |
Blueprint | BP_ | 常规蓝图 |
Material | M_ | 材质 |
StaticMesh | S_ | 静态网格体 |
SkeletalMesh | SK_ | 骨骼网格体 |
Texture | T_ | 纹理 |
ParticleSystem | PS_ | 粒子系统 |
WidgetBlueprint | WBP_ | 组件蓝图 |
文件夹命名规则
|--项目名称
|-- Maps
|-- Textures
|-- Blueprints
|-- Effects (particle)
|-- Animations
|-- Sounds
|-- Sources
我们建议,在引擎根目录进行细致的命名分化。以打到高效管理资产的目的,命名应遵循清晰,准确,简短的描述分类内容。尽量不要使用模糊描述。项目名称作为最顶层文件夹名称
命名规范网站
https://github.com/uejoy/ue4-style-guide
UE游戏世界中存在元素的根源,用来表示世界中的任何物体的高级抽象类,由Actor进行创建,Component进行行为组件,完成整个游戏世界的元素展示
Actor是一个载体,Component组件是能力
Acotr的创建方式为两种,第一种为直接在场景中编辑拖拽(静态创建),优势无需编码,更加直观简单,缺点可能影响游戏启动速度,增加场景构建负担。第二种为通过编码动态进行生成(动态创建,例如扔手雷)相对于前者复杂度上升,但可控性更强,动态生成的Actor会持有有效的操作指针,我们可以根据实际情况进行生成,更加灵活
SpawnActor函数
在蓝图中我们借助SpawnActorOfClass进行动态生成Actor,在C++中我们需要通过UWorld指针进行创建。在UWorld类中,我们可以找到多个生成Actor的函数。对于重载函数,我们根据特定的情况进行选择即可。SpawnActor函数是个工厂函数,下面地址中可以查到UWorld的相关API
http://api.unrealengine.com/INT/API/Runtime/Engine/Engine/UWorld/index.html
API——用户接口手册(描述类的结构)
生成Actor
首先我们需要获取到UWorld世界对象指针。对于每一个在场景中存在的对象,本身都具备获取UWorld指针的能力,我们只需要调用GetWorld函数即可获得UWorld对象指针。记得引入头文件(UWorld本身头文件已经在父类中被包含,所以无需额外引入)
StaticClass
合成函数,获取一个UClass指针。旨在将操作类作为一个参数进行传递(传递模板)。虚幻中除了使用模板构建对象外,还增加了映射关系,可以将类作为对象构建依据,这可以方便的将类提供给蓝图使用
注意:C++本身是编译型语言,我们在编译器中看到的文件类并不是真正的C++类,只是编译后生成的映射文件
组件的构建优于BeginPlay
删除ACTOR方式
Destroyed
LifeSpan
消亡ACTOR通知方式
Destroyed
当对象被删除时(非内存删除)进行回调操作
EndPlay
对象被彻底清除时回调,回调会进行删除类型通知
删除类型如下:
Destroyed 当Actor或Component彻底被删除时(内存中)
LevelTransition 关卡切换时删除回调(非关卡流)
EndPlayInEditor 编辑器关闭时,回调通知
RemovedFromWorld 关卡流切换被释放时调用
Quit 游戏退出时被删除回调
借助全局变量GEngine指针调用函数AddOnScreenDebugMessage即可完成屏幕输出
例1:GEngine->AddOnScreenDebugMessage(-1, 3, FColor::Blue, TEXT("OK"));
例2:GEngine->AddOnScreenDebugMessage(-1, 3, FColor::Blue, TEXT("O"),true);
GEngine->AddOnScreenDebugMessage(-1, 3, FColor::Blue, TEXT("K"),true);//OK
例3:GEngine->AddOnScreenDebugMessage(-1, 3, FColor::Blue, TEXT("OK"),true,FVector2D(5,5));//OK放大5倍
Key如果是-1则添加新的消息,不会覆盖旧有消息
如果不是-1则更新现有消息,效率更高
bNewerOnTop当Key为-1时有效,直接添加到队列最上层
false为添加到队列最尾端
TEXT宏
虚幻中用来构建非对象型字符串的关键宏,构建结果是与平台无关的宽字符串(类似C语言字符串),借助对象FString带参构造函数TCHAR类型指针来构建FString对象字符串
各个平台的字符串格式不同,所以用TEXT宏,实质是L“字符串”,即宽字符串
编译的中文不打印的解决办法
文件里高级保存选项里面简体中文改成UTF-8带签名
没有就在工具,自定义,命令,添加命令,文件,高级保存项添加进去
头文件的注意
1.对应源文件的头文件在最顶端
2.generated头文件在最末尾
帮助我们记录数据信息,方便追溯,文件在Saved里的Log的最近的文件里,backup可以删
通过使用宏UE_LOG进行控制台日志输出(日志会写入本地缓存)。构建日志需要传入三个参数
1.日志分类(可以自定义)
1.决定了内容输入到控制台时的分类项
2.日志类型冗余度,分为
1.Fatal(会终止进程)致命错误
2.Error(会终止进程)错误问题
3.Warning(黄色)、Display(白色)、Log(白色)(较常用的日志分类项)
4.Verbose(将日志详细信息记录到日志文档,但不向控制台输出)(比较快)
5.VeryVerbose(将日志详细信息记录到日志文档,但不向控制台输出)
3.日志内容
分两步:声明和定义
1.声明自己日志分类
DECLARE_LOG_CATEGORY_EXTERN(CategoryName,DefaultVerbosity,CompileTimeVerbosity);
CategoryName自定义日志分类名称 Log开头
DefaultVerbosity日志默认级别,一般使用Log
CompileTimeVerbosity日志编译级别,高于此级别的不会被编译,一般用All
此操作需要在头文件中完成,并且只需要完成一次即可
此宏用来生成日志分类结构体对象,只需要在头文件中进行一次操作即可
例子1:DECLARE_LOG_CATEGORY_EXTERN(ZLog,Log,All);
2.定义日志分类
DEFINE_LOG_CATEGORY(CategoryName);
此操作必须在CPP文件中进行,只需要进行一次定义即可
例子1:DEFINE_LOG_CATEGORY(ZLog);
以上操作必须均具备方可
简化日志输出
借助宏构建红可以编写更加简单的日志输入方式
类似C语言中的printf输出,在虚幻中UE_LOG支持可变参数进行构建复杂语句格式,通过占位符,进行输入导入,用来编写更加清晰的日志语句
占位符
%d 整数输出
%f 浮点数输出
%s 输出UE类型字符串(非对象型字符串FString)
例子:UE_LOG(UE4Log,Log,TEXT("小明今年%d岁,身高%f厘米,在%s上学"),20,165.5f,TEXT("奥里给学校"))
编写带有可变参数的自定义日志
_VA_ARGS_可变参数宏,在宏中用来接收可变参数,将可变参数进行传递
可以借助此宏编写更加简单的日志输出宏
Log_Display(mes,...) UE_LOG(FLLog,Display,TEXT(msg),##_VA_ARGS_);
为了方便跨平台,UE对于C++基本数据类型进行深度重定义,方便平台扩展特性,增加UE的移植便捷性
禁止在UE中使用C++的基本数据类型,这样会影响引擎的跨平台特性
bool代表布尔值(永远不要假设布尔值的大小),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的大小)
编码是信息从一种形式或格式转换为另一种形式的过程,也称为计算机编程语言的代码简称编码。用预先规定的方法将文字、数字或其他对象编成数码,或将信息、数据转换成规定的电脉冲信号。编码在电子计算机、电视、遥控和通讯等方面广泛使用。解码,是编码的逆过程
文本在进行储存时会选择文本的格式。文本常用表示格式分为二进制(无格式),文本(ASCII),UTF-8,UTF-16
虚幻引擎4中的所有字符串都作为FStrings或TCHAR数组以UTF-16格式存储在内存内。大多数代码假设2个字节等于一个代码点,因此只支持基本多文种平面(BMP),这样虚幻内部编码可以更准确地描述为UCS-2。字符串以适合于当前平台的字节次序存储。
当向从磁盘序列化到程序包,或在联网期间序列化时,TCHAR字符小于0xff的字符串均存储为一串8位字节,否则存储为双字节UTF-16字符串。序列化代码可以根据需要处理任何字节次序转换
UE4中提供多种字符类型进行数据处理,在不同的情景下,我们需要选择不同的类型进行操作
区别:大小不同,编码方式不同,所有的文本在进行存储的时候,编译器编译阶段会根据编码类型进行转码
字符类型:
typedef FPlatformTypes::ANSICHAR ANSICHAR;
typedef FPlatformTypes::WIDECHAR WIDECHAR
typedef FPlatformTypes::TCHAR TCHAR;
typedef FPlatformTypes::CHAR8 UTF8CHAR;
typedef FPlatformTypes::CHAR16 UCS2CHAR;
typedef FPlatformTypes::CHAR16 UTF16CHAR;
typedef FPlatformTypes::CHAR32 UTF32CHAR;
转码宏:
有些时候,我们需要主动的进行转码操作,这是很有必要的,虚幻中提供了一些转码操作宏,来帮助我们进行转码操作
#define TCHAR_TO_ANSI(str) (ANSICHAR*)StringCast
#define ANSI_TO_TCHAR(str) (TCHAR*)StringCast
#define TCHAR_TO_UTF8(str) (ANSICHAR*)FTCHARToUTF8((const TCHAR*)str).Get()
#define UTF8_TO_TCHAR(str) (TCHAR*)FUTF8ToTCHAR((const ANSICHAR*)str).Get()
1.FName,资源命名字符串,FName通过一个轻型系统使用字符串。在此系统中,特定字符串即使会被重复使用,在数据表中也只存储一次。FNames不区分大小写(大小写不是他比较的依据)。它们为不可变,无法被操作。应用:资产名称
FNames的存储系统和静态特性决定了通过键进行FNames的查找和访问速度较快。FName子系统的另一个功能是使用散列表为FName转换提供快速字符串
2.FText表示一个显式字符串,用户的显示文本都需要由FText进行处理。支持格式化文本,不提供修改函数,无法进行内容修改。UI上的文本都是FText,UI只用做一套,可以做国际化。应用:UI拿来显示文本(特性:支持被宏序列化,可以国际化操作)
3.FString,可以被操作的字符串。开销大雨其他类字符串类型。应用:最灵活,FString可以转FNames或FText,FString可以扩容、调整、变化、转化的文本存储器
构建方式:
FString str=FString(TEXT("ok"));
FString str1(TEXT("ok"));
FString str2;
UELog里用FString转TCHAR
UE_LOG(LogTemp,Log,TEXT("%s"),*str);
其他数据类型转换到FString
FVector Loc(10,20,30);
Loc.ToString();
FRotator Rot(4,5,3);
Rot.ToString();
FString::SanitizeFloat(3.32f);
FString::FormatAsNumber(112323);//每3位就会,一下 112,323
FString::FromInt(5);
bool b=true;
b?TEXT("true"):TEXT("false");
FString转到整型、浮点型
FString a(TEXT("50"));
FCString::Atoi(*a);
FCString::Atof(*a);//转换到浮点型
大部分F开头的对象都有ToString的方法,可以直接输出ToString
FString比较
if(str1==str2)
{};//区分大小写
if(str1.Equals(str2,ESearchCase::IgnoreCase))
{};//忽略大小写
检查已有的字符串是否包含给定的内容
FString str1(TEXT("ABCDEFG"));
FString str2(TEXT("FG"));
if(str1.Contains(str2)){}; //查找内容,是否忽略大小写,查询方向
检查已有字符串在已有的字符串中出现的位置
str1.Find(str2) //查找内容,是否忽略大小写,查询方向,起始位置,返回值,如果包含给定的字符串,则返回字符串出现的位置,如果不包含,返回-1
裁切
FString str(TEXT("A*B*C*D*E"));
FString Left;
FString Right;
str.Split(TEXT("*"),&Left,&Right);
Left+Right;
Left+=Right;
检查字符串是否为空
str.IsEmpty();
路径拼接符
//str=A! Left=A 结果是A!/A
str/Left;
拼接
FString Msg=FString::Printf(TEXT("我有%02d 你有%50d"),1,123); //我有01 你有123
FName不区分大小写
构建方式
FName n1=FName(TEXT("AB"));
FName n2(TEXT("AB"));
if(n1==n2){};
*n1.ToString()
用户显示文本→构建UI的信息展示
FText名称空间相同没问题,但键值不能相同
构建方式
第一种:(希望内容显示在面板上则用宏构建)
#define LOCTEXT_NAMESPACE "TEXT_UE4" //声明text名称空间,放在文件最顶端,空间名称的主要目的是为了缩小搜索范围
FText tex=LOCTEXT("KEY","B") //第一个参数是键值,第二个是内容,键值目的是为了帮助找到翻译的内容
#undef LOCTEXT_NAMESPACE //将声明的空间名称宏进行释放,放在文件最末端
第二种:(希望内容显示在面板上则用宏构建)
FText tex=NSLOCTEXT("TEXT_UE4","KEY","ABC") //提供三个参数 空间名称,键值,内容
第三种:(只是在用内容做转移或操作)
FText tex=FText::GetEmpty();
tex=tex1;
数字型数据转换成FText
FText::AsNumber(60);
FText::As好多
FText比较
FText f1=NSLOCTEXT(“UECPP”,"Key","AB");
FText f2=NSLOCTEXT("UECPP","Key","ab")
f1.EqualTo(f2); //包含检查大小写,false
f1.EqualToCaseIgnored(f2); //忽略大小写,true
格式化Text(拼接的目的是为了产出一个FText)
第一种方案:占位符拼接
FText ft2=NSLOCTEXT("TEXT_UE4","KEY2","b");
FText ft3=NSLOCTEXT("TEXT_UE4","KEY3","c");
FText ft1=FText::Format(NSLOCTEXT("UECPP","KEY","a+{0}+{1}"),ft2,ft3); //a+b+c
UE_LOG(LogTemp,Log,TEXT(“%s”),*ft1.ToString());
第二种方案:参数拼接
例子1:
FFormatArgumentValue arg(f1);
FText ft1=FText::Format(NSLOCTEXT("UECPP","KEY","a+{0}"),arg);
UE_LOG(LogTemp,Log,TEXT("%s"),*ft1.ToString());
例子2:
FFormatArgumentValue arg;
arg.Add(TEXT("name"),tex);
arg.Add(TEXT("hp"),f1);
FText ft1=FText::Format(NSLOCTEXT("UECPP","KEY","a+{name}+{hp}"),arg);
UE_LOG(LogTemp,Log,TEXT("%s"),*ft1.ToString());
三者间的转换
FString
从FString转换到FName
FString s1(TEXT("OK"));
FName n1=FName(*s1);
FString到FText(不会参与国际化操作的翻译)
FText t1=FText::FromString(s1);
FName
FName到FString
FName n1(TEXT("name"));
FString s1=n1.ToString();
FName到FText
FText t1=FText::FromName(n1);
FText
FText到FString
FText t1=NSLOCTEXT("U","K","NAME");
FString s1=t1.ToString();
FText到FName是不存在转换的,先转换成FString,再转到FName
FString s1=t1.ToString();
FName n1=FName(*s1);
注册执行指令(只能在gamemode.h或playercontroller.h里写)
UFUNCTION(Exec)
void SayHello(int32 Num);
UE4编辑器里 独立进程启动下
窗口——本地化控制板——从文本文件收集——添加搜索目录(source)——添加语言——选择当前VS里的文本的语言——收集文本——选择需要翻译成的语言里的编辑此语言的翻译——在平移里输入翻译的文字——保存——计算字数——编译文本
根据设定改变语言版本 独立进程启动下
项目偏好设置里的播放里的额外启动参数改为-calture=en (英文)
=后面的在内容中的Localization——Game的文件夹里有缩写
改变资产的语言版本 独立进程启动下
增加一个文本渲染器——设置细节里的文本——本地化控制板——同上的操作
游戏中动态改变语言版本
GameMode.h文件中
UFUNCTION(Exec)
void ChangeLan(FString Lan); //写一个切换语言的执行指令
GameMode.cpp文件中
void ACceshiGameModeBase::ChangeLan(FString Lan)
{
FInternationalization::Get().SetCurrentCulture(Lan); //设置当前游戏的语言环境
}
容器是方便我们存储数据的载体,在虚幻中,为我们提供了三种容器。分别是TArray,TMap,TSet。首先虚幻提供的容器都是同质容器,只能用来存储相同类型的数据。三种容器具备不同的特性,我们可以根据使用场景选择操作的容器
虚幻中的容器使用泛型特性进行构建,可以装填大部分数据类型,并且具有丰富的操作API
TArray UE中的数组
数组中的位置为0,1,2,3。数组中元素的个数为1,2,3,4
最常用的数据容器,特点速度快,内存消耗小,安全性高
TArray被称为同质容器:其所有元素均完全为相同类型,不能进行不同元素类型的混合
TArray被设计成值类型,无法被继承。不要使用new和delete进行创建销毁。元素也是数值类型,为容器拥有。TArray被销毁时元素也被销毁。从一个TArray创建新的TArray变量,将把元素复制到新的变量中,不存在共享状态(加进去的内容元素和原来的地址不同,值相同)
初始化
注意:容器在构建时,不要构建为堆对象,直接构建为栈对象。由于容器是模板类,在构建时必须指出存储数据类型
TArray
Array.Init(TEXT("d"),10); //向容器添加10个元素,元素内容是"d"
遍历
Num函数可以获取TArray当前元素个数。TArray重载了运算符[],通过位置下标可以访问到对应位置元素
例1:
for(int32 i=0;i
{
UE_LOG(LogTemp,Log,TEXT("%s"),*Array[i]);
}
例2:语法糖遍历
for(auto& s1:Array)
{
UE_LOG(LogTemp,Log,TEXT("%s"),*s1);
}
修改
Array[0]=TEXT("ss");
添加元素
Add,Emplace,AddUnique函数均可以向数组中添加元素(到末尾),元素被添加时,内存从分配器中被分配。Add和Emplace函数可达到同样的效果,但存在细微不同
Add把一个元素类型实例复制左值引用(或移动右值引用)到数组中
Emplace添加元素到容器中,Add函数调用的时Emplace函数
AddUnique向容器中加入唯一元素
Append函数可以复制普通的数组到容器中(普通数组,数组中元素的个数)
TArray
Array.Add(TEXT("OK"));
Array.Add(TEXT("OK"));
Array.Emplace(TEXT("OK"));
Array.AddUnique(TEXT("ok")); //string比较忽略大小写,如已有元素则失败返回-1,成功返回元素位置
FString Data[3]{TEXT("ed"),TEXT("ab"),TEXT("ss")};
Array.Append(Data,ARRAY_COUNT(Data)); //ARRAY_COUNT宏只能用来看普通数组的长度
//数组中OK OK OK ed ab ss
Insert允许在给定索引添加一个单一元素或元素数组的一个副本(如果插入位置超过容器大小将会报错)
Array.Insert(TEXT("A"),5);
SetNum主动设置容器的大小,如果长度大于原容器大小,空白位置将用模板类型默认对象填充。如果小于原容器大小,则超过设置大小的内容将被删除(容器的大小,是否允许缩小容器当前元素数量)
Array.SetNum(15,true);
迭代器
容器中的元素是一个一个排好队的,迭代器相当于指向每个元素的箭头,目的是获取元素,具备++特性
迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器(container,例如链表或阵列)上遍访的接口,设计人员无需关心容器的内容
TArray、TMap、TSet有两种迭代器,一种是可以通过迭代器修改元素内容,一种是只能读取元素不能修改元素
禁止在迭代器中修改容器的元素个数,禁止添加和移除元素
普通迭代器构建:
for(auto It=Array.CreateIterator();It;++It) //注意++位置要放前面
{
*It; //迭代器指向的元素内容,*It是取出元素,Array.CreatIterator()创建一个迭代器
UE_LOG(LogTemp,Log,TEXT("==%s"),**It);
}
常量迭代器构建:
for(auto It=Array.CreateConstIterator();It;++It) //注意++位置要放前面
{
//迭代器指向的元素内容,*It是取出元素,Array.CreatConstIterator()创建一个常量迭代器
UE_LOG(LogTemp,Log,TEXT("==%s"),**It);
}
Array转成普通数组
返回类型指针,指针地址是数组中第一个元素的地址(数组进行传递的时候传递的是指针——地址)
FString* Data=Array.GetData();
常规查询函数
Array.IsValidIndex(5); //返回布尔值,查询指定位置是否存在有效元素
Array.Last(); //返回最后的元素
Array.Last(5); //返回倒数第5个元素
Array.Top(); //返回顶端元素,没有Top(1)这种
Array.Contains(TEXT("ok")); //查找是否包含给定的元素并返回布尔值
Array.Find(TEXT("OK")); //查找是否包含给定的元素并返回元素所在位置,不包含返回-1
int32 Index =0;
Array.Find(TEXT("OK"),Index); //查询给定元素所在的位置将位置索引设置到Index,返回布尔值
常规移除函数
TArray有Reset函数,清除内容,但保留空间
Array.Remove(TEXT("OK")); //在容器中移除给定的元素,返回移除的个数
Array.RemoveSingle(TEXT("OK")); //在容器中移除一个给定的元素,返回移除的个数,0移除失败1移除成功
Array.RemoveAt(5); //移除给定位置的元素
Array.Empty(); //清空容器
UE中最常用的容器,此容器是关联型容器,存储对象均有一个关联值,通过键值可以高效的进行对象访问
TMap为同质容器,存储类型必须相同,TMap也是值类型,支持常规复制、赋值和析构函数操作,以及其元素较强的所有权。映射被销毁时,其元素也将被摧毁。键类型必须为值类型,不能使用指针
Map的结构例如钥匙和锁,一把钥匙找一把锁,他们之间是一一对应的关系
构建
构建时需要选择好容器的键值类型和元素类型,添加时必须提供键值。如果添加的数据键值已经存在则会覆盖之前的添加
TMap
map.Add(TEXT("N1"),99); //向容器中添加元素,允许添加相同键值内容,但会覆盖
map.Add(TEXT("N1")); //允许只填入键值不添加数据元素(将使用默认数据填充)
mao[TEXT("N1")]=90; //可以使用此方法修改数据内容,但是不能添加键值
合并TMap(值类型必须相同)
Append合并操作,传入的Map如果有和被合并的Map键值相同数据,将采取覆盖操作
map.Append(map2); //将map2合并到map
遍历操作
注意迭代器
例1:
for(auto& Item:map)
{
//Item.Key;
//Item.Value;
}
例2:
for(auto It=map.CreateIterator();It;++It)
{
It.Key(); //获得键值
It.Value()=200; //获得值,返回的是引用,可以在外部修改,注意语法
It->Value; //也可以获得值
}
例3:
for(auto It=map.CreateConstIterator();It;++It)
{
It.Key; //获得键值
It.Value(); //获得值,禁止修改
}
查询函数
map.Num(); //获取容器中元素的数量
map[TEXT("n1")]; //通过索引运算符使用键值获得引用,可以用来修改元素内容
map.Contains(TEXT("n1")); //检查是否包含给定的键值 返回布尔值
map.Find(TEXT("n1")); //返回键值绑定的元素指针,如果没有内容返回空,非返回引用
移除函数
TMap有Reset函数,清除内容,但保留空间
map.Rempve(TEXT("n1")); //使用给定键值移除元素
map.Empty();
TSet也是键值容器和TMap类似,但速度快,无需提供单独的键进行关联元素,不允许有重复的键
TSet也是值类型,支持常规复制、赋值和析构函数操作,以及其元素较强的所有权。集合被销毁时,其元素也将被销毁。键类型也必须是值类型
与TArray的区别
1.TSet是KV容器
2.TSet不保证数据填充顺序
3.TSet数组存储时无法重复存储,TArray可以
构建
TSet
set.Add(TEXT("OK")); //添加内容
合并
TSet
set.Append(set2); //允许合并操作
遍历
例1:
for(auto&Item:set)
{
Item=TEXT("n1"); //操作元素内容
}
例2:
for(auto It=set.CreatIterator();It;++It)
{
*It=TEXT("n1"); //操作元素内容
}
例3:
for(auto It=set.CreatConstIterator();It;++It)
{
*It; //获取内容,但禁止修改
}
查询函数
set.Num(); //获取容器中元素的数量
set.Contains(TEXT("n1")); //检查元素中是否包含给定的键值
set.Find(TEXT("n1")); //如果查找某一元素是否存在,建议可直接使用Find函数进行单一查找,返回找到指向元素的指针,未找到返回空
set.Array(); //将TSet容器转为TArray容器
移除函数
set.Reset(); //移除元素,但不释放空间
set.Remove(TEXT("n1")); //移除给定的键值内容
set.Empty(); //移除所有元素,释放空间
常规性的数据存储,一般情况下我们用TArray(有谁在场景里,小队里有谁)
Array有序容器,位置关系不会变化,通过下标访问到元素
TMap关键字索引(武器镶嵌),通过键值访问到元素
TSet敏感词检查(玩家名字重复)
Array容器(数组)可以自动变化大小的容器
Map容器(映射)具有键值的同质容器(键值可以是枚举)对于元素操作需要依靠键值,键值是map的操作标签。键值类型可以是蓝图常规对象类型
元素类型必须相同,键值唯一。也就是加入相同键值元素将被覆盖
应用:背包栏(具备格子概念)技能栏(技能施放快捷键)装备槽等
Set容器(集)键值类同质容器。键值和元素相同,本身对键值操作隐藏。操作标签即为元素本身,即如果想要操作set中的内容,需要先知道元素。这与其他两种容器思考方式完全不同 只检查元素存不存在
应用:聊天辱骂过滤,创建名字敏感词检索,特殊道具持有检查等