Unreal Engine: 从文件路径加载静态网格物体
Unreal Engine: Load static mesh from file path
美好的一天!我刚开始学习 Unreal Engine 4.12 一周。供您自行决定-我对 C++ 编程知之甚少。 (尽管我使用 PHP 进行编码,所以我在某种程度上理解了 OOP)- 而且,我只是对可视化脚本(蓝图)有点熟悉。
我想要做的是通过加载一个新的静态网格物体来改变玩家的武器,该静态网格物体将来自文件路径.目前没有执行此操作的蓝图节点,许多 articles/forums 建议构建我自己的蓝图节点。
我做了一些研究,发现了这个:Dynamic Load Object C++ - 它非常有前途 - 但是,我不知道如何实施它。我尝试打开 MyProject.h 并将其粘贴到那里,但我不确定下一步该怎么做 - 它会变成一个函数吗?还是蓝图节点?
我愿意接受关于如何实现我想要的目标的其他建议(或方向)。如果还有其他方法可以实现这一点,请分享和教育我。非常感谢!
此致,
克里斯
静态负载只是帮手。只有用 UFUNCTION(...) 宏标记该函数的 header 才能调用 C++ 函数。参见 this link。
所以您可以创建您的函数并在它的实现中调用该帮助程序。例如:
// 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
}
但是您需要问问自己,是否真的需要对其进行硬编码。您可以指定类似
的内容
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Widgets")
TSubclassOf<class UObjectWidget> wInGameMenu;
UPROPERTY(BlueprintReadOnly, Category = "Widgets")
UObjectWidget* InGameMenu;
在覆盖函数 BeginPlay 的地方(这是由于动态创建 小部件 )我有:
if (wInGameMenu)
{
InGameMenu = CreateWidget<UObjectWidget>(this, wInGameMenu);
}
UObjectWidget 是 UUserWidget 的继任者,我的小部件(在编辑器中创建)被重新设置为将该小部件作为继承基础。我定义了应该在我的 object 的 archetype 上创建哪个小部件。
我会这样实现它:(如果有人告诉我更好的方法,这可能会改变)
- 创建 WeaponManager 作为 ActorComponent
- 创建 Weapon 作为 SceneComponent(这样你就可以将它附加到骨架插座上)
- 每个 Weapon 都会有它自己的基于相同接口的实现(可能覆盖共同祖先中定义的一些函数?)
- 您可以拥有多个 sub-childs(能量武器、射击武器等),这样您就有了正确的继承并且避免了同一事物的多次实现。
- 每个 Weapon 都会定义它的网格和属性 - 同样,如果你硬编码网格路径(没关系,因为它是实现),你可以在最后使用这样的代码那个列表)或者你可以在原型上设置它,如果你想在蓝图中编码一些东西。
- 然后在WeaponManager中定义所有武器(例如
TArray<TSubclassOf<UWeapon>>
- 每个武器都应该定义 EWeaponType - 枚举游戏中的所有武器,这样我就可以将定义的武器与其在 TMap 中的类型匹配,然后根据需要简单地使用它(显示,隐藏、更换武器等)该类型应该硬编码到武器的所有实现中。
在构造函数中加载网格:
//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);
}
美好的一天!我刚开始学习 Unreal Engine 4.12 一周。供您自行决定-我对 C++ 编程知之甚少。 (尽管我使用 PHP 进行编码,所以我在某种程度上理解了 OOP)- 而且,我只是对可视化脚本(蓝图)有点熟悉。
我想要做的是通过加载一个新的静态网格物体来改变玩家的武器,该静态网格物体将来自文件路径.目前没有执行此操作的蓝图节点,许多 articles/forums 建议构建我自己的蓝图节点。
我做了一些研究,发现了这个:Dynamic Load Object C++ - 它非常有前途 - 但是,我不知道如何实施它。我尝试打开 MyProject.h 并将其粘贴到那里,但我不确定下一步该怎么做 - 它会变成一个函数吗?还是蓝图节点?
我愿意接受关于如何实现我想要的目标的其他建议(或方向)。如果还有其他方法可以实现这一点,请分享和教育我。非常感谢!
此致,
克里斯
静态负载只是帮手。只有用 UFUNCTION(...) 宏标记该函数的 header 才能调用 C++ 函数。参见 this link。
所以您可以创建您的函数并在它的实现中调用该帮助程序。例如:
// 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
}
但是您需要问问自己,是否真的需要对其进行硬编码。您可以指定类似
的内容UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Widgets")
TSubclassOf<class UObjectWidget> wInGameMenu;
UPROPERTY(BlueprintReadOnly, Category = "Widgets")
UObjectWidget* InGameMenu;
在覆盖函数 BeginPlay 的地方(这是由于动态创建 小部件 )我有:
if (wInGameMenu)
{
InGameMenu = CreateWidget<UObjectWidget>(this, wInGameMenu);
}
UObjectWidget 是 UUserWidget 的继任者,我的小部件(在编辑器中创建)被重新设置为将该小部件作为继承基础。我定义了应该在我的 object 的 archetype 上创建哪个小部件。
我会这样实现它:(如果有人告诉我更好的方法,这可能会改变)
- 创建 WeaponManager 作为 ActorComponent
- 创建 Weapon 作为 SceneComponent(这样你就可以将它附加到骨架插座上)
- 每个 Weapon 都会有它自己的基于相同接口的实现(可能覆盖共同祖先中定义的一些函数?)
- 您可以拥有多个 sub-childs(能量武器、射击武器等),这样您就有了正确的继承并且避免了同一事物的多次实现。
- 每个 Weapon 都会定义它的网格和属性 - 同样,如果你硬编码网格路径(没关系,因为它是实现),你可以在最后使用这样的代码那个列表)或者你可以在原型上设置它,如果你想在蓝图中编码一些东西。
- 然后在WeaponManager中定义所有武器(例如
TArray<TSubclassOf<UWeapon>>
- 每个武器都应该定义 EWeaponType - 枚举游戏中的所有武器,这样我就可以将定义的武器与其在 TMap 中的类型匹配,然后根据需要简单地使用它(显示,隐藏、更换武器等)该类型应该硬编码到武器的所有实现中。
在构造函数中加载网格:
//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);
}