zoukankan      html  css  js  c++  java
  • [UE4]C++实现动态加载的问题:LoadClass<T>()和LoadObject<T>() 及 静态加载问题:ConstructorHelpers::FClassFinder()和FObjectFinder()

    转自:http://aigo.iteye.com/blog/2281558

    动态加载UObject和动态加载UClass分别用LoadObject<T>(),和LoadClass<T>() ,两者均在在UObjectGlobals.h中。

    另外注意:LoadClass<T>的模版名称,不能直接写UBlueprint,例如:LoadClass<UBlueprint>是错误的,创建蓝图时选择的是什么父类,则写对应的父类名,假如是Actor,那么要写成:LoadClass<AActor>,否则无法加载成功。

    路径名也必须带_C后缀(LoadObject不需要带_C后缀),例如,蓝图路径是:Blueprint'/Game/Blueprints/MyBP.MyBP'

    加后缀以后,则是:Blueprint'/Game/Blueprints/MyBP.MyBP_C',

    例子:

    UClass* Test = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Blueprints/MapPathBrush_BP.MapPathBrush_BP_C'"));  

    官方还没出文档,只能先看代码注释:

    // Load an object.  
    template< class T >   
    inline T* LoadObject( UObject* Outer, const TCHAR* Name, const TCHAR* Filename=nullptr, uint32 LoadFlags=LOAD_None, UPackageMap* Sandbox=nullptr )  
    {  
        return (T*)StaticLoadObject( T::StaticClass(), Outer, Name, Filename, LoadFlags, Sandbox );  
    }  
    // Load a class object.  
    template< class T >   
    inline UClass* LoadClass( UObject* Outer, const TCHAR* Name, const TCHAR* Filename=nullptr, uint32 LoadFlags=LOAD_None, UPackageMap* Sandbox=nullptr )  
    {  
        return StaticLoadClass( T::StaticClass(), Outer, Name, Filename, LoadFlags, Sandbox );  
    }  
    /** 
     * Find or load an object by string name with optional outer and filename specifications. 
     * These are optional because the InName can contain all of the necessary information. 
     * 
     * @param ObjectClass   The class (or a superclass) of the object to be loaded. 
     * @param InOuter       An optional object to narrow where to find/load the object from 
     * @param InName        String name of the object. If it's not fully qualified, InOuter and/or Filename will be needed 
     * @param Filename      An optional file to load from (or find in the file's package object) 
     * @param LoadFlags     Flags controlling how to handle loading from disk 
     * @param Sandbox       A list of packages to restrict the search for the object 
     * @param bAllowObjectReconciliation    Whether to allow the object to be found via FindObject in the case of seek free loading 
     * 
     * @return The object that was loaded or found. NULL for a failure. 
     */  
    COREUOBJECT_API UObject* StaticLoadObject( UClass* Class, UObject* InOuter, const TCHAR* Name, const TCHAR* Filename = NULL, uint32 LoadFlags = LOAD_None, UPackageMap* Sandbox = NULL, bool bAllowObjectReconciliation = true );  
    COREUOBJECT_API UClass* StaticLoadClass(UClass* BaseClass, UObject* InOuter, const TCHAR* Name, const TCHAR* Filename = NULL, uint32 LoadFlags = LOAD_None, UPackageMap* Sandbox = NULL);  

     LoadObject加载例子,不需要添加后缀:

    UTexture2D* Tex = LoadObject<UTexture2D>(NULL, TEXT("Texture2D'/Game/Textures/UI/tex_test001.tex_test001'"));  

    可以用LoadObject加载的文件包括:

    Texture、Material、SoundWave、SoundCue、ParticlesSystem、AnimMontage、BlendSpace(1D,2D,3D)、AnimSequence、AnimBlueprint、SkeletalMesh等等。这些文件的父类都是UObject,所以也可以先加载为UObject*然后再强转为具体的类型,例如:

    UObject* Obj = LoadObject<UObject>(NULL, TEXT("SkeletalMesh'/Game/MyMesh.MyMesh'"));  
    USkeletalMesh* MyMesh = Cast<USkeletalMesh*>(Obj);  

    实现动态加载UObject:StaticLoadObject();以Texture和Material为例

    示例1:

    动态加载Object的工具方法

    UTexture2D* MyTextureLoader::LoadTextureFromPath(const FString& Path)  
    {  
        if (Path.IsEmpty()) return NULL;  
      
        return Cast<UTexture2D>(StaticLoadObject(UTexture2D::StaticClass(), NULL, *(Path)));  
    }  
    调用:
    FString PathToLoad = "/Game/Textures/YourStructureHere";  
    UTexture2D* tmpTexture = LoadTextureFromPath(PathToLoad);  

    示例2:
    加载MaterialTexture

    struct FConstructorStatics  
     {  
         ConstructorHelpers::FObjectFinderOptional<UTexture> TextureFinder;  
         ConstructorHelpers::FObjectFinderOptional<UMaterial> MaterialFinder;  
         FConstructorStatics()  
             : TextureFinder(TEXT("Texture2D'/Game/Textures/2DBackground.2DBackground'"))  
             , MaterialFinder(TEXT("Material'/Game/Materials/DynamicTextureMaterial.DynamicTextureMaterial'"))  
         {  
         }  
     };  
     static FConstructorStatics ConstructorStatics;  
       
     Texture = ConstructorStatics.TextureFinder.Get();  
     UMaterial* Material = ConstructorStatics.MaterialFinder.Get();  
     DynamicMaterial = UMaterialInstanceDynamic::Create(Material, this);  

    设置调用加载好的Material和Texture:

    DynamicMaterial->SetTextureParameterValue(FName("DynamicTexture"), Texture);  
    Mesh->SetMaterial(0, DynamicMaterial);  
     

    如果资源永不再使用,想销毁资源对象,代码如下:

    Texture2D* mytex; //这里假设mytex合法有效  
      
    mytex->ConditionalBeginDestroy();  
    mytex = NULL;  
    GetWorld()->ForceGarbageCollection(true);  

    Dynamic Asset Loading with C++

    https://www.youtube.com/watch?v=pJIAmSGxfmQ

    Dynamic Load Object

    https://wiki.unrealengine.com/Dynamic_Load_Object

    [UE4]C++静态加载问题:ConstructorHelpers::FClassFinder()和FObjectFinder()

    这里说的静态加载指的是必须在构造函数中完成的加载方式,动态加载值得是可以在Runtime期间加载的方式,UE4源码里面,前者其实是对后者的一层封装,即FObjectFinder()是对LoadObject()的封装。But,FClassFinder()不是对LoadClass()的封装,FClassFinder()内部调用的是LoadObject()。

    如果要获取某个蓝图BP的类型class,可以通过ConstructorHelpers::FClassFinder()来获取,例如:

     
    static ConstructorHelpers::FClassFinder<AActor> UnitSelector(TEXT("Blueprint'/Game/MyProject/MyBlueprint.MyBlueprint'"));  
    TSubclassOf<AActor> UnitSelectorClass = UnitSelector.Class;  

    但是在启动游戏时会报错提示找不到文件,例如:

    Default property warnings and errors:

    Error: COD Constructor (MyGameMode): Failed to find /Game/MyProject/MyBlueprint.MyBlueprint

    解决办法有两种(这是UE4的一个坑,浪费了我很长时间。。。):

    A,在copy reference出来的文件路径后面加_C,例如:Blueprint'/Game/Blueprints/MyBlueprint.MyBlueprint_C'

    static ConstructorHelpers::FClassFinder<AActor> UnitSelector(TEXT("Blueprint'/Game/Blueprints/MyBlueprint.MyBlueprint_C'"));  
    TSubclassOf<AActor> UnitSelectorClass = UnitSelector.Class;  

    B,去掉路径前缀:/Game/Blueprints/MyBlueprint

    static ConstructorHelpers::FClassFinder<AActor> UnitSelector(TEXT("/Game/Blueprints/MyBlueprint"));  
    TSubclassOf<AActor> UnitSelectorClass = UnitSelector.Class;  

    另外注意:FClassFinder<T>的模版名称,不能直接写UBlueprint,例如:FClassFinder<UBlueprint>是错误的。创建蓝图时选择的是什么父类,则写对应的父类名,假如是Actor,那么要写成:FClassFinder<AActor>,否则无法加载成功。

    使用TSubclassOf<T>时模板名必须相同

    另外, FClassFinder<T>()函数中的模版名必须和TSubclassOf<T>变量的模版名一样,例如上面的都是AActor,如果不一样,也会出现上面的错误。
    再给个例子:

    static ConstructorHelpers::FClassFinder<UUserWidget> TestBP(TEXT("/Game/Blueprints/MyWidget_BP"));  
    TSubclassOf<UUserWidget> MyWidgetClass = TestBP.Class;  

    也可使用UClass*替换TSubclassOf<T>

    例如:

    static ConstructorHelpers::FClassFinder<UUserWidget> TestBP(TEXT("/Game/Blueprints/MyWidget_BP"));  
    UClass* MyWidgetClass = TestBP.Class;  

    之前看到很多例子是通过FObjectFinder()来获取class,现在想想感觉是无奈之举,UE4的文档比较坑,不仅蓝图的文档更新不同步,C++的文档更是少得可怜。

    static ConstructorHelpers::FObjectFinder<UBlueprint> UnitSelector(TEXT("Blueprint'/Game/MyProject/MyBlueprint.MyBlueprint'"));  
    TSubclassOf<AActor> UnitSelectorClass = (UClass*)UnitSelector.Object->GeneratedClass;  

    其他参考:

    CDO Constructor: Failed to find Blueprint

    https://answers.unrealengine.com/questions/84880/cdo-constructor-failed-to-find-blueprint-ue-44.html

  • 相关阅读:
    apollo使用场景2
    我问问
    洛谷 P3979 遥远的国度
    小技巧—对拍和输出文件的比较
    洛谷 P6850 NOI
    小技巧—双向边快速枚举
    ZJOI 2008 骑士
    小技巧—指数形式的枚举
    小技巧—滚动数组
    刷题心得—背包问题的枚举方式
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/7728194.html
Copyright © 2011-2022 走看看