[UE C++] Enum的使用
前言
在UE中,Enum的定义方法有两种,一种是C++ 11的enum class风格,一种是传统的枚举风格。定义UEnum的方法也比较简单,只需加上UENUM()
宏标记即可
1. 定义Enum
推荐使用enum class定义枚举,不仅限定了作用域,还有其它优势
//传统enum
namespace EMyTestEnum
{
enum Type
{
One,
Two,
Three
};
}
//C++ 11 enum class
enum class EMyTestEnum
{
One,
Two,
Three
};
以上是原生C++枚举,只能在C++中使用且不能被UE反射和序列化。
//传统风格UEnum
UENUM()
namespace EMyTestEnum
{
enum Type
{
One,
Two,
Three
};
}
//enum class UEnum
UENUM()
enum class EMyTestEnum
{
One,
Two,
Three
};
加了UENUM()
后,UE会在编译时自动生成辅助代码,运行时会创建一个UEnum的UObject对象。这时我们就可以通过FindObject
查找枚举类型的对象,在运行时对UENnum按名查找,取值,转换为字符串等操作
如果在蓝图中也需要使用该枚举,需要加上BlueprintType
。且对于enum class创建的枚举,必须将枚举类型定义为uint8(不加默认为int),不然编译不会通过
//传统风格UEnum
UENUM(BlueprintType)
namespace EMyTestEnum
{
enum Type
{
One,
Two,
Three
};
}
//enum class UEnum
UENUM(BlueprintType)
enum class EMyTestEnum : uint8
{
One,
Two,
Three
};
对于枚举中的元素,我们可以使用UMETA
来对它进行修饰,常用的是DisplayName
修改显示名字,下面只以enum class枚举为例
UENUM(BlueprintType)
enum class EMyTestEnum : uint8
{
None,
One = 10 UMETA(DisplayName = "First"),
Two = 20 UMETA(DisplayName = "Second"),
Three = 30 UMETA(DisplayName = "Three")
};
同时需要注意,公开到蓝图的UEnum(BlueprintType)必须存在一个值为0的枚举值,不然编译会报错。下面这种就会报错,因为One = 1,导致枚举值从1开始累加,不存在值为0的枚举值。如果只是单纯在C++中使用(不加BlueprintType),则没有这个要求
UENUM(BlueprintType)
enum class EMyTestEnum : uint8
{
One = 1 UMETA(DisplayName = "First"),
Two UMETA(DisplayName = "Second"),
Three UMETA(DisplayName = "Three")
};
2. 通过反射获得枚举信息
以enum class为例,首先声明枚举类型,定义枚举变量
UENUM(BlueprintType)
enum class EMyTestEnum : uint8
{
None,
One = 10 UMETA(DisplayName = "First"),
Two = 20 UMETA(DisplayName = "Second"),
Three = 30 UMETA(DisplayName = "Three")
};
EMyTestEnum MyTestEnum = EMyTestEnum::One;
在开始之前还需要通过FindObject
查找枚举类型的对象,(FindObject
会在内存中查找对象,找到就会返回,找不到会返回nullptr,不会触发加载)
const UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EMyTestEnum"), true);
2.1 GetNameStringByValue
作用:根据value得到枚举名
//打印 Two
UE_LOG(LogTemp, Warning, TEXT("%s"),*EnumPtr->GetNameStringByValue(20));
存在GetNameByValue
,输出的是FName
无效Value返回空值
2.2 GetValueByNameString
作用:根据枚举名得到value
//打印 30
UE_LOG(LogTemp, Warning, TEXT("%d"), EnumPtr->GetValueByNameString(FString("Three")));
存在GetValueByName
,输入的是FName
无效Name返回-1
2.3 GetValueByIndex
作用:根据index得到value,注意index和value的区别
//打印 10,index从0开始计算
UE_LOG(LogTemp, Warning, TEXT("%d"), EnumPtr->GetValueByIndex(1));
无效index会触发Assert
2.4 GetIndexByValue
作用:根据value得到index
//打印 3
UE_LOG(LogTemp, Warning, TEXT("%d"), EnumPtr->GetIndexByValue(30));
无效value返回-1
2.5 Some More
index value Name NameString 都存在可以相互转化的API,这里就不一一列举了
2.6 有效性
IsValidEnumValue
与IsValidEnumName
//false
EnumPtr->IsValidEnumValue(80);
//true
EnumPtr->IsValidEnumName(FName("Three"));
2.7 GetMaxEnumValue与NumEnums
作用:获得Value最大值和Enum的个数
这里划重点:UE会为我们定义的UEnum增加一个MAX枚举,这个枚举在UEnum的最后一个index,我们可以访问它,在这个例子中,我定义了None,One,Two,Three 4个枚举,UE会自动生成一个EMyTestEnum_MAX,它的值是我们定义的枚举的最大值+1,EMyTestEnum_MAX=30+1,它的 index = 3+1。GetMaxEnumValue
获得的是它的值,即为31。NumEnums
也计算了它的存在,即为4+1
UE_LOG(LogTemp, Warning, TEXT("%s"), *EnumPtr->GetNameStringByValue(31));
UE_LOG(LogTemp, Warning, TEXT("%d"), EnumPtr->NumEnums());
UE_LOG(LogTemp, Warning, TEXT("%d"), EnumPtr->GetMaxEnumValue());
2.8 GetDisplayNameTextByIndex
作用:根据index获得枚举的DisplayName
//打印First
UE_LOG(LogTemp, Warning, TEXT("Enum:%s"), *EnumPtr->GetDisplayNameTextByIndex(1).ToString());
还存在GetDisplayNameTextByValue
,也可以通过GetMetaData
达到类似的效果(但这个是EditorOnly,打包不能用)
//2是index,打印Second
UE_LOG(LogTemp, Warning, TEXT("Enum:%s"), *EnumPtr->GetMetaData(TEXT("DisplayName"), 2));
3. 通过反射获得蓝图定义的枚举
蓝图定义的枚举同样会放在内存中,所以我们同样可以通过FindObject
获得,但是这里存在一点问题,具体解答可看UE4 填坑系列之:C++获取蓝图定义枚举类型
枚举定义:
C++代码:
const UEnum* EnumPtr = FindObject<UUserDefinedEnum>(ANY_PACKAGE, TEXT("E_EnumTest"), true);
if (EnumPtr)
{
UE_LOG(LogTemp, Warning, TEXT("Successfully"));
UE_LOG(LogTemp, Warning, TEXT("%s"), *EnumPtr->GetNameStringByValue(0));
UE_LOG(LogTemp, Warning, TEXT("%s"), *EnumPtr->GetDisplayNameTextByIndex(0).ToString());
}
最后
本篇文章较为基础,希望能帮到大家。若有错误,欢迎指出。封面来自于网络,侵权必删