Chris Javier Oliveros
Chris Javier Oliveros

Reputation: 227

Unreal Engine: Load static mesh from file path

Good day! I just started studying Unreal Engine 4.12 for a week now. For your discretion - I have little knowledge in C++ programming. (Although I code using PHP so I understanding OOP to some extent) - and, I'm just getting a little familiar with visual scripting (blueprint).

What I want to do is change the players weapon by loading a new static mesh, that static mesh would be from a file path. There are currently no blueprint node that does that, many articles/forums are suggesting to build my own blueprint node.

I've done some research and I have found this: Dynamic Load Object C++ - and it is very promising - but, I have no knowledge of implementing it. I tried opening MyProject.h and pasted it there, I'm not sure what to do next - does it become a function? Or a blueprint node?

I 'am open to other suggestions (or directions) on how to achieve what I wanted. If there are other methods to achieve this, please share and educate me. Thank you very much!

Sincerely,

Chris

Upvotes: 3

Views: 10489

Answers (1)

Pavel Pája Halbich
Pavel Pája Halbich

Reputation: 1583

That static load is only helper. You can call C++ function only if you mark header of that function by UFUNCTION(...) macro. See this link.

So you can create your function and in it's implementation, you can call that helper. For example:

// Helpers.h
static FORCEINLINE UTexture2D* GetTexture2DByName(const FName& name) {
    return LoadObjFromPath<UTexture2D>(name);
}

UFUNCTION(BlueprintCallable, Category = TCF2Helpers)
    static UTexture2D* GetTexture2DForBlock(UBuildableBlockInfo* blockInfo);


// Helpers.cpp
UTexture2D* UHelpers::GetTexture2DForBlock(UBuildableBlockInfo* blockInfo)
{
    if (!blockInfo)
        return nullptr;

    const FString baseFolder = TEXT("Texture2D'/Game/Textures/HUD/%s");

    if (blockInfo->IsEmptyHand)
        return GetTexture2DByName(*FString::Printf(*baseFolder, TEXT("EmptyHand.EmptyHand'")));

    // another lines of implementation
}

But you need to ask yourself, if you really need to have it hardcoded. You can specify something like

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Widgets")
    TSubclassOf<class UObjectWidget> wInGameMenu;

UPROPERTY(BlueprintReadOnly, Category = "Widgets")
    UObjectWidget* InGameMenu;

where in override of function BeginPlay (this is due to creating widget on the fly) I have:

if (wInGameMenu)
{
    InGameMenu = CreateWidget<UObjectWidget>(this, wInGameMenu);
}

UObjectWidget is successor of UUserWidget and my widgets (created in Editor) are reparented to have that widget as an inheretance base. I define which widget should be created on archetype of my object which holds it.

I'd implement it like that: (this may be changed if anyone tells me better way)

  • Create WeaponManager as ActorComponent
  • Create Weapon as SceneComponent (so you can attach it on skeleton socket)
  • Every Weapon will have it's own implementation based on same interface (maybe override of some functions defined in common ancestor?)
  • You can have multiple sub-childs (Energy weapon, shooting weapon etc) so you have correct inheritance and you avoid multiple implementation of same thing.
  • Every Weapon will define it's mesh and properties - again, if you hardcoded mesh path (it's OK since it is implementation), you can use code like that in the end of that list) or you can set that on archetype, if you'd like to code something in blueprint.
  • Then in WeaponManager you define all weapons (for example TArray<TSubclassOf<UWeapon>>
  • Every Weapon should define EWeaponType - enum af all weapons in game, so I can match defined weapons with it's type in TMap and then simply work with it on demand (show, hide, change weapon etc.) That type should be hardcoded to all implementations of weapons.

Load mesh in constructor:

//TerminalObject.h
UCLASS()
class TAUCETIF2_API ATerminalObject : public AStaticMeshActor
{
    GENERATED_UCLASS_BODY()
};

// TerminalObject.cpp
ATerminalObject::ATerminalObject(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{

    static ConstructorHelpers::FObjectFinder<UStaticMesh> mesh(TEXT("StaticMesh'/Game/BuildingObjects/Meshes/terminal.terminal'"));

    checkf(mesh.Succeeded(), TEXT("Failed to find mesh"));

    auto mc = GetStaticMeshComponent();
    checkf(mc, TEXT("Failed to find mesh component"));

    mc->SetStaticMesh(mesh.Object);
}

Upvotes: 2

Related Questions