高站网站建设,网站返回顶部代码,中国建筑企业排名,统计局网站建设情况文章目录前言一、原生c的枚举类型关键字classint8 - 枚举的基础类型#xff08;underlying type#xff09;二、枚举类型的灵活运用位运算枚举循环遍历三、虚幻风格的枚举类型UENUMUMETATEnumAsByte总结前言
虚幻引擎中的代码部分实现了一套反射机制#xff0c;为c代码带了…
文章目录前言一、原生c的枚举类型关键字classint8 - 枚举的基础类型underlying type二、枚举类型的灵活运用位运算枚举循环遍历三、虚幻风格的枚举类型UENUMUMETATEnumAsByte总结前言
虚幻引擎中的代码部分实现了一套反射机制为c代码带了更多方便的特性。本篇文章将会着眼于其中更加细节的部分——虚幻中的enum。
在虚幻风格的代码中我们经常能使用这样的方法来创建枚举类型
UENUM(BlueprintType)
enum class EMyEnum : uint8
{Option1 UMETA(DisplayName Option 1),Option2 UMETA(DisplayName Option 2),Option3 UMETA(DisplayName Option 3)
};似乎有一些c的影子但又好像有一些不一样的部分。它有基本c的框架但又有一些额外的东西。如果你对c很熟悉那再好不过。只需要始终把握一点一切还是源于c额外的内容的目的是将该类型加入到反射系统中使其支持序列化使其能够支持蓝图编辑。
一、原生c的枚举类型
我们来先将上面的例子简化一下
enum EMyEnum
{Option1,Option2,Option3
};这是我们最熟悉的枚举创建方法EMyEnum是枚举的名字。
下面是它一般的使用方式
// Example use of the enum
void MyFunction()
{EMyEnum MyOption Option1;if (MyOption Option2){// Do something}
}
接下来我们一点一点为它扩展。
关键字class
首先添加关键字class。
enum class EMyEnum
{Option1,Option2,Option3
};在这个例子中我们的枚举类型EMyEnum有三个具体的选项Option1Option2和Option3。其中class关键字的作用是说明这是一个有作用范围作用域的枚举scoped enum意思是枚举的值需要在枚举类型的作用范围内使用具体如下
// Example use of the enum
void MyFunction()
{EMyEnum MyOption EMyEnum::Option1;if (MyOption EMyEnum::Option2){// Do something}
}int8 - 枚举的基础类型underlying type
可以利用int8确定枚举值的基本类型
enum class EMyEnum : int8
{Option1,Option2,Option3
};这意味着每个枚举值都会以一个8位的整型值来表示。其他可用基本类型还有uint8uint16uint32int16int32等等。
那这有什么用呢比如说希望判断枚举值是否在某个范围内或者是多个枚举值之间进行比较的时候。
下面看一个具体的例子
enum class EDamageType : uint8
{Blunt,Piercing,Fire,Ice,Electric,Poison
};我们创建了一个表示伤害类型的枚举当然从游戏的层面来讲枚举值可能远远不止这些。
这里我们可以利用和符号来判断枚举值是否在一个范围内比如
EDamageType DamageType EDamageType::Fire;if (DamageType EDamageType::Electric)
{// Do something for non-electric damage types
}
else
{// Do something for electric damage type
}例子中只要待判断的伤害类型属于BluntPiercingFire或Ice中的任何一个判断条件都将成立因为他们都小于Electric。
更直观的我们将每个枚举值的默认uin8都写出来
enum class EDamageType : uint8
{Blunt 0,Piercing 1,Fire 2,Ice 3,Electric 4,Poison 5
};在进行比较或者范围判定的时候实际上是这些枚举值背后的数字在进行判断。
当然也可以不使用默认值而用任意指定的值比如
enum class EDamageType : uint8
{Blunt 100,Piercing 200,Fire 300,Ice 400,Electric 500,Poison 600
};可以使用static_cast或reinterpret_cast来进行枚举类型和其基础类型之间的显示转换
EDamageType DamageType EDamageType::Fire;
uint8 DamageTypeValue static_castuint8(DamageType);那么如果不指定基本类型会怎么样像一开始那样直接将这个省略会有什么结果
答案是编译器会根据枚举值自动为它挑选合适的基本类型所以似乎省略也没有什么不妥甚至为书写方便了不少。但是还是推荐在书写的时候指明基本类型否则可能会有一些类型匹配方面的问题亦或是出现一些无法预测的行为。
二、枚举类型的灵活运用
除了上面介绍的特性和基本应用枚举还有一些其他好玩的用法。
位运算
利用位运算可以快捷得将枚举值分配为以2为系数的等比数列从而可以将枚举值表示为二进制码的组合比如
enum class EMyFlags : uint8
{None 0,Flag1 1 0,Flag2 1 1,Flag3 1 2,Flag4 1 3,Flag4 1 5,All Flag1 | Flag2 | Flag3 | Flag4,
};在这个例子中每个标志都进行左移运算即每一个值都是前一个值的2倍。可以利用位运算符号|^对这些枚举值进行组合。All就是所有标志组合的结果将它与其中某个枚举值进行运算即可判断它是否包含该枚举值
EMyFlags MyFlag EMyFlags::Flag1;
if (EMyFlags::All MyFlag)
{// Do something
}这里的结果自然是通过的。
枚举循环遍历
在c 11的新特性中可以对枚举类型的值使用循环遍历如
for (EMyEnum Value : TEnumRangeEMyEnum())
{// Do something with Value
}在这个例子中TEnumRange模板提供了一种遍历所有EMyEnum的枚举值的方式。
三、虚幻风格的枚举类型
虚幻在基础c枚举的基础上也加入了自己风格的代码这自然也为它添加了更多的功能和特性。
这里以一个游戏中典型的枚举为例
UENUM(BlueprintType)
enum class EWeaponType : uint8
{Pistol UMETA(DisplayName Pistol),Shotgun UMETA(DisplayName Shotgun),RocketLauncher UMETA(DisplayName Rocket Launcher)
};EWeaponType是该枚举类型的名称PistolShotgunRocketLauncher是具体的枚举值。
UENUM
UENUM将枚举类型进行标记方便UHT为其生成相应的类型文件生成反射系统需要的代码。BlueprintType说明符令该枚举可以在蓝图中自如使用。
UMETA
使用UMETA宏来指定每个枚举值指定一个显示名即在蓝图使用中和UI中显示的名称。
TEnumAsByte
虚幻引擎还提供了一种特殊类型的枚举称为TEnumAsByte用于加强类型安全并且解决一些常见的错误主要是一些将枚举类型强行用作其基础类型的应用场合例如意外使用枚举作为数组的索引。
TEnumAsByteEWeaponType Weapon EWeaponType::Shotgun;这里就声明了一个TEnumAsByteEWeaponType类型的枚举变量Weapon它本身其实是一个结构体其中只有一个简单的uint8类型的字段。这是一种典型的面向对象的做法用一个类型对象将数据封装这样当你用一个枚举值去为另一个枚举值赋值的时候就会报错了这种做法进一步保证了类型安全。
在将枚举类型变量公布给蓝图使用时通常需要将它与基本枚举类型结合起来进行类型的声明。
总结
枚举类型是一种强大的编程工具可以使你的代码更加清晰、简洁、易于维护。在使用时要注意选择适当的技巧以确保你的代码能够正常工作并避免潜在的错误。
希望文中的例子可以帮助更多人更好地了解如何在编写代码时使用枚举类型。