関連ブログ
- [UE5] 元の位置に戻るカメラの実装 2024.12.18UE
- [UE5]難易度変更に対応したシューティングゲームを作ってみよう 2024.12.11UE
- [UE5] インタラクト可能なモノの量産に役立つBPを作ってみよう 2024.12.04UE
CATEGORY
2024.01.31UE5UE/ C++
執筆バージョン: Unreal Engine 5.3
|
今回は、StructUtils Plugin 内で実装されている FInstancedStruct を紹介します。
FInstancedStruct を使うと、
本来多態的な利用が想定されていない構造体 (USTRUCT) を、
インスタンス化された UObject* プロパティのように
多態的に利用できるようになります。
……と書いてもよくわからないと思うので、簡単な使用例を示して解説しようと思います。
※ StructUtils Plugin は Experimental 扱いです。
今後仕様が変更される可能性がありますのでご注意ください。
StructUtils Plugins が有効になっていない場合は、Unreal Engine の Editor を開き、
Edit → Plugins → Struct Utils のチェックをオンにして再起動してください。
UE 5.3 では本 Plugin は (Experimental にも関わらず) 最初から有効になっています。
本 Plugin を利用して実装されている LocalizableMessage Plugin が
デフォルトで有効な設定になっているためだと思われます。
また、プロジェクトの .Build.cs を編集し、
PublicDependencyModuleNames に “StructUtils” を追加します。
1 2 3 4 5 6 7 8 9 10 |
public class 《プロジェクト名》 : ModuleRules { public 《プロジェクト名》(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "StructUtils" }); // ← 追加 //(省略) } |
球や三角柱といった立体図形の情報を 1 つ保持し、
その名称および体積をデバッグ出力する
Actor 継承クラス “AMyActor” を作成することにします。
コードは以下のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "InstancedStruct.h" #include "Math/UnrealMathUtility.h" // PI (円周率) 使用のため #include "MyActor.generated.h" // 立体図形を表す構造体 (基底) USTRUCT(BlueprintType) struct FSolidStruct { GENERATED_BODY() // 体積を求めて返す関数 virtual float CalculateVolume() const { return 0; } // 立体図形の名前を返す関数 virtual void GetSolidName(FString& OutName) const { OutName = TEXT(""); } }; // 球を表す構造体 (派生) USTRUCT(BlueprintType) struct FSphereStruct : public FSolidStruct { GENERATED_BODY() // 半径 UPROPERTY(BlueprintReadWrite, EditAnywhere) float Radius; // 体積を求めて返す関数 (4/3 * 円周率 * 半径^3) float CalculateVolume() const override { return 4.0f / 3.0f * PI * FMath::Pow(Radius, 3.0f); } // 立体図形の名前を返す関数 ("sphere") void GetSolidName(FString& OutName) const override { OutName = TEXT("sphere"); } }; // 三角柱を表す構造体 (派生) USTRUCT(BlueprintType) struct FTriPrismStruct : public FSolidStruct { GENERATED_BODY() // 底面の三角形の底辺 UPROPERTY(BlueprintReadWrite, EditAnywhere) float BaseWidth; // 底面の三角形の高さ UPROPERTY(BlueprintReadWrite, EditAnywhere) float BaseHeight; // 三角柱の高さ UPROPERTY(BlueprintReadWrite, EditAnywhere) float PrismHeight; // 体積を求めて返す関数 ((底面の底辺 x 底面の高さ ÷ 2) * 柱の高さ) float CalculateVolume() const override { return BaseWidth * BaseHeight / 2.0f * PrismHeight; } // 立体図形の名前を返す関数 ("triangular prism") void GetSolidName(FString& OutName) const override { OutName = TEXT("triangular prism"); } }; UCLASS() class MYPROJECT_API AMyActor : public AActor { GENERATED_BODY() public: AMyActor(); protected: virtual void BeginPlay() override; // 立体図形の体積の計算結果をデバッグ表示する関数 UFUNCTION(BlueprintCallable) void PrintSolidVolumeCalcResult(); public: // 立体図形情報を扱う FInstancedStruct UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (BaseStruct = "/Script/MyProject.SolidStruct", ExcludeBaseStruct)) FInstancedStruct SolidInstance; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include "MyActor.h" AMyActor::AMyActor() { PrimaryActorTick.bCanEverTick = true; } void AMyActor::BeginPlay() { Super::BeginPlay(); PrintSolidVolumeCalcResult(); } void AMyActor::PrintSolidVolumeCalcResult() { if (!SolidInstance.IsValid()) { return; } const FSolidStruct& Solid = SolidInstance.Get(); FString SolidName; Solid.GetSolidName(SolidName); const float Volume = Solid.CalculateVolume(); const FString ResultString = FString::Printf(TEXT("The volume of the %s is %.2f cm^3."), *SolidName, Volume); GEngine->AddOnScreenDebugMessage(INDEX_NONE, 10.0f, FColor::Red, ResultString); } |
球を表す構造体 FSphereStruct と三角柱を表す構造体 FTriPrismStruct が
立体図形を表す構造体 FSolidStruct の派生として宣言・定義されており、
それぞれ体積を返す関数と立体図形名を返す関数を override しています。
また、AMyActor が宣言・定義されており、
立体図形の名称および体積をデバッグ出力する関数
PrintSolidVolumeCalcResult() を
BeginPlay() で呼ぶようになっています。
AMyActor に立体図形の情報を保持させるために
FInstancedStruct のメンバ変数を宣言しています。
該当のコードは MyActor.h の以下の部分です。
1 2 3 |
// 立体図形情報を扱う FInstancedStruct UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (BaseStruct = "/Script/MyProject.SolidStruct", ExcludeBaseStruct)) FInstancedStruct SolidInstance; |
UPROPERTY のメタデータ指定子によって、
Editor 上で SolidInstance の値を設定する際に選択可能な構造体を
FSolidStruct の派生構造体 (FSphereStruct と FTriPrismStruct) に限定しています。
『BaseStruct = “/Script/MyProject.SolidStruct”』が
選択可能な構造体を FSolidStruct およびその派生構造体
(FSolidStruct, FSphereStruct, FTriPrismStruct) に限定する記述で、
『ExcludeBaseStruct』が
BaseStruct で指定した構造体自体 (FSolidStruct) を
選択可能な構造体から除外する記述となります。
『”/Script/MyProject.SolidStruct”』の部分は
「MyProject モジュールの FSolidStruct 構造体を指定する」という意味です。
構造体名から接頭辞 F を除いて指定する必要があるので注意してください。
FInstancedStruct から実態の構造体にアクセスする部分のコードは
MyActor.cpp の以下の部分です。
1 |
const FSolidStruct& Solid = SolidInstance.Get(); |
ここでは const 参照を取得しており、
以降はこれを利用して FSolidStruct のメンバ関数を呼び出しています。
参照ではなくポインタで取得することも可能です。
取得関数の一覧を以下に示します。
const | 非 const | |
参照 | Get<型>() | GetMutable<型>() |
ポインタ | GetPtr<型>() | GetMutablePtr<型>() |
AMyActor を Parent とする Blueprint (BP_MyActor) を作成し、
Details Panel から SolidInstance の項目を確認してみます。
FSolidStruct の派生構造体が選択可能になっており、
選択すると下部に対応するメンバ変数が列挙され、それぞれ値を変更できるようになっています。
(“Tri Prism Struct” 選択時の表示 ↓)
(“Sphere Struct” 選択時の表示 ↓)
また、BP_MyActor を Level に配置して Play すると、
選択した構造体の種類に応じてデバッグ出力結果が変化しています。
構造体 (USTRUCT) を多態的に利用できることが確認できました。
FInstancedStruct について、簡単な使用例を示しました。
StructUtils Plugin は Experimental 扱いではありますが、
既に多数の Engine Plugin が本 Plugin を利用して実装されているため、
今回紹介することにしました。
FInstancedStruct 以外にも汎用的な機能が用意されているので、
興味があればソースコードを覗いてみてください。