当前位置:   article > 正文

虚幻引擎(UE4) 反射系统(Reflection)_虚幻反射

虚幻反射

反射是程序在运行时检查自身的能力。这是非常有用的,并且是虚幻引擎的基础技术,可以为许多系统提供动力,例如编辑器中的详细信息面板,序列化,垃圾收集,网络复制以及Blueprint / C ++通信。但是,C ++本身不支持任何形式的反射,因此Unreal拥有自己的系统来收集,查询和操纵有关C ++类,结构,函数,成员变量和枚举的信息。我们通常将反射称为属性系统,因为反射也是图形术语。

反射系统是可选的。您需要注释任何您希望在反射系统中可见的类型或属性,虚幻解析工具(UHT)会在编译项目时获取该信息。

 

标记

要将.h头文件标记为包含反射类型,请在头文件顶部添加一行特殊的包含目录:#include“ FileName.genic.h”并且需要将此包含项放在其他include之后。这使UHT知道他们应该考虑该文件,并且对于系统的实现也是必需的。

现在,您可以使用宏:UENUM(),UCLASS(),USTRUCT(),UFUNCTION()和UPROPERTY()在头文件中注释不同类型的成员变量和函数。每个宏都位于类型或成员声明之前,并且可以包含其他说明符关键字。让我们看一个真实的例子(来自StrategyGame):

  1. //移动单元(士兵)的基类
  2. #include“ StrategyTypes.h”
  3. #include“ StrategyChar.genic.h”
  4. UCLASS(描述)
  5. class AStrategyChar : public ACharacter, public IStrategyTeamInterface
  6. {
  7. GENERATED_UCLASS_BODY()
  8. /** Pawn死亡后获得多少资源收益 */
  9. UPROPERTY(EditAnywhere, Category = “Pawn”)
  10. int32 ResourcesToGather;
  11. /** 设置武器插槽附件 */
  12. UFUNCTION(BlueprintCallable, Category=“Attachment”)
  13. void SetWeaponAttachment(class UStrategyAttachment* Weapon);
  14. UFUNCTION(BlueprintCallable, Category=“Attachment”)
  15. bool IsWeaponAttached();
  16. protected:
  17. /** 进展动画 */
  18. UPROPERTY(EditDefaultsOnly, Category=“Pawn”)
  19. UAnimMontage* MeleeAnim;
  20. /** 装备插槽 */
  21. UPROPERTY()
  22. UStrategyAttachment* ArmorSlot;
  23.   /** 团队编号 */
  24. uint8 MyTeamNum;
  25. };

此头文件声明了一个继承自ACharacter的新类,称为AStrategyChar。它使用UCLASS()来表示它已被反射,它也与下面的类AStrategyChar定义中的宏GENERATED_UCLASS_BODY()配对。反射类或结构中需要GENERATED_UCLASS_BODY()或者GENERATED_USTRUCT_BODY()宏,因为这样做,虚幻将会把引擎额外的内容(包括函数和Typedef宏)注入到类主体中。

显示的第一个属性是ResourcesToGather,它用EditAnywhere和Category = Pawn注释。这意味着该属性可以在编辑器的任何详细信息面板中进行编辑,并将显示在Pawn类别中。带有BlueprintCallable函数,这意味着可以从蓝图Blueprints中调用它们。

MyTeamNum未申明反射属性,这里要注意,非反射属性对于所有依赖反射的系统都是不可见的(例如,存储未反射的原始UObject指针)通常很危险,因为垃圾收集器看不见你的引用)。

每个说明符关键字(例如EditAnywhere或BlueprintCallable)都在ObjectMacros.h中进行枚举,并对含义或用法进行简短注释。如果不确定关键字的作用,选中关键字,Alt + G通常可以带您进入ObjectMacros.h中的定义(它们不是真正的C ++关键字,但是Intellisense或VAX依然能带你查看定义)。

常见的UPROPERTY说明符关键字如下:

  • Category:“类别”。指定变量属于哪个类别,这个非常有用,当你使用C++派生一个蓝图类时,蓝图中显示太多的成员变量会让你眼花缭乱,Category会让这些变量被归类并显示到蓝图中,让你很快就能查找到变量。

  • EditAnywhere:任何地方可编辑。声明了此关键字,你将会在蓝图中的任何地方编辑此变量的值。否则不能编辑它。

  • VisibleAnywhere:任何地方可见。声明了此关键字,你将会在蓝图的任何地方可见此变量。否则是不可见的。

  • BlueprintReadOnly:蓝图中只读。

  • BlueprintReadWrite:蓝图中可读可写。

  • BlueprintCallable:蓝图中可以调用。

常见的UFUNCTION说明符关键字如下:

  • Category:和UPROPERTY中的Category关键字一样,唯一不同就是这里是为函数分类,上面是成员变量分类。

  • BlueprintCallable:蓝图中可以调用。

 

局限性

UHT不是真正的C ++解析器。它能理解该语言的一部分,并积极地尝试跳过所有可能的文本。只关注反射的类型,函数和属性。但是,有些事情仍让会它迷惑,因此在将反射类型添加到现有头文件时,您可能不得不重新编写某些单词或将其包装在 #if CPP  ...  #endif 中。您还应该避免在任何带注释的属性或函数周围使用#if /#ifdef(WITH_EDITOR和WITH_EDITORONLY_DATA除外),因为生成的代码会引用它们,并且在定义不正确的任何配置中都会导致编译错误。

 

使用反射

大多数游戏代码可以在运行时忽略属性系统,从而享受其功能强大的系统的好处,但是在编写工具代码或构建游戏系统时,您可能会发现它很有用。

反射属性系统的类型层次结构如下所示:

  1. UField
  2. UStruct
  3. UClass(C ++类)
  4. UScriptStruct(C ++结构)
  5. UFunction(C ++函数)
  6. UEnum(C ++枚举)
  7. UProperty(C ++成员变量或函数参数)
  8. (许多不同类型的子类)

UStruct是复合结构的基本类型,因此不应该与C++结构(UScriptStruct)混淆。UClass可以包含函数或属性作为其子级,而UFunction和UScriptStruct仅限于属性。

你可以用过调用UTypeName::StaticClass()或FTypeName::StaticStruct()来获取对象的类型(UClass或UScriptStruct),同时你也可以用过实例Instance->GetClass()来获取UObject的类型。遍历UStruct的所有成员,使用TFieldIterator

  1. for (TFieldIterator <UProperty> PropIter(GetClass()); PropIter; ++ PropIter)
  2. {
  3. UProperty* property= *PropIter;
  4. //todo
  5. }

TFieldIterator的模板参数用作过滤器(因此您可以使用UField或仅使用一个或另一个查看属性和函数)。迭代器构造函数的第二个参数指示您是只希望遍历在指定的类/结构中的字段还是在父类/结构中的字段(默认);它对功能没有任何影响。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/133261
推荐阅读
相关标签
  

闽ICP备14008679号