[UE C++] Enum的使用

[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 有效性

IsValidEnumValueIsValidEnumName

//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++获取蓝图定义枚举类型

枚举定义:
E_EnumTest
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());
}

结果

最后

本篇文章较为基础,希望能帮到大家。若有错误,欢迎指出。封面来自于网络,侵权必删

参考链接

猜你喜欢

转载自blog.csdn.net/qq_52179126/article/details/129891590
今日推荐