Edited at

UE4 UnrealC++でのアセットの扱い方についてのメモ


概要

UnrealEngine の BPアクターやアセットデータを UnrealC++ で扱うためのメモ書きです。

C++からアクターやアセットをスポーンする場合を書いていますが、実際使う場合そのアセットのロードやパッケージ化時の参照に問題がでることがありますので別途対応が必要です。


修正履歴

日付
内容

2019/08/30
サウンドデータ取得について追記


環境

Windows10

Visual Studio 2017

UnrealEngine 4.22


参考

以下を参考にさせて頂きました、ありがとうございます。

アセットの参照

[UE4] C++で動的にアクターを生成(スポーン)する方法で一番実用的だった方法


BPアクターをC++から扱う


BPアクターをC++からスポーンする1

対象のBPファイルクラスのメンバ宣言です。


.h

UPROPERTY()

TSubclassOf<AActor> BP_Var;

ランタイム時とエディタ時でBPファイルを探すConstructorHelpersでの処理が違います。

また、ファイルパスは /Game/ や /Plugin/ などから開始しないとならないようで、/Content/は省略します。

(例) {Project名}/Content/Test/TestActor.uasset -> /Game/Test/TestActor


.cpp

// コンストラクタ

#if UE_GAME
// ランタイム
static ConstructorHelpers::FClassFinder<AActor> BluePrintFile(TEXT("/Game/Test/TestActor"));
if (BluePrintFile.Class) {
BP_Var = (UClass*)BluePrintFile.Class;
}
#else
// エディター
static ConstructorHelpers::FObjectFinder<UBlueprint> BluePrintFile(TEXT("Blueprint'/Game/Test/TestActor.TestActor'"));
if (BluePrintFile.Object) {
BP_Var = (UClass*)BluePrintFile.Object->GeneratedClass;
}
#endif

// スポーンするメソッド
// アクターをスポーンする
AActor* MyClass = GetWorld()->SpawnActor<AActor>(BP_Var, FVector(0.0f, 0.0f, 0.0f), FRotator(0.0f, 0.0f, 0.0f));


サンプルコードでは取得したBPクラス(BP_Var)のnullptrチェックを行っていないことに注意。


BPアクターをC++からスポーンする2

対象のBPファイルクラスのメンバ宣言です。


.h

UPROPERTY()

TSubclassOf<class AActor> SubClass;

ファイルパス設定は TEXT("")マクロを使うか、"/Game/Blueprint/CharaBP.CharaBP_C" のように接尾語 _C を付与します。


.cpp

// コンストラクタ

// クラスを取得
SubClass = TSoftClassPtr<AActor>(FSoftObjectPath (TEXT("/Game/Blueprint/CharaBP"))).LoadSynchronous();

// スポーンするメソッド
// コンストラクタで取得したクラスを用いてアクタを生成
ActorSpawnParameters SpawnInfo; // パラメータ設定
AActor* Instance = GetWorld()->SpawnActor<AActor>(SubClass , SpawnInfo);


この方法ではエディタ時とランタイム時での処理の差異はありませんでした。


アセットデータをC++から扱う


DataTable型のデータをC++から取得する

DataTableの元になる構造体です。

このstructを元にアセットブラウザからデータテーブル型のアセットを作成します。


.h

USTRUCT(BlueprintType)

struct FMyDataTable : public FTableRowBase
{
GENERATED_USTRUCT_BODY()

public:
// コンストラクタ
FMyDataTable(){}

public:
// アイテムID
UPROPERTY(Category = "Test", EditAnywhere, DisplayName = "Param1")
int32 Param1;
// 存続時間[sec]
UPROPERTY(Category = "Test", EditAnywhere, DisplayName = "Param2")
float Param2;

};


読み込み処理をするC++クラスです。


.h

UDataTable* TestData;


TestParamがデータテーブル型のアセットです。


.cpp

// コンストラクタ

static ConstructorHelpers::FObjectFinder<UDataTable> DataTableFile(TEXT("/Game/Test/TestParam.TestParam'"));
if(DataTableFile.Object){
TestData = DataTableFile.Object;
}

// 取得
TArray<FMyDataTable*> OutAllRows;
FString _Context; // エラー時用
TestData->GetAllRows<FMyDataTable>(_Context, OutAllRows);
for (FMyDataTable* _InfoRow : OutAllRows)
{
UE_LOG(LogTemp, Warning, TEXT("%d, %f"), _InfoRow->Param1, _InfoRow->Param2);
}



テスクチャデータをC++から取得する

[ui]フォルダにある test00.uasset というテクスチャデータを取得する例です。


.cpp

// コンストラクタ

class UTexture2D* Tex;

static ConstructorHelpers::FObjectFinder<UTexture2D> _DataFile(TEXT("/Game/ui/test00"));
if (_DataFile.Object) {
Tex = _DataFile0.Object;
}



カーブデータをC++から取得する

NewCurveBase.uassetという浮動小数カーブのデータを取得する例です。


.cpp

// コンストラクタ

UCurveFloat* Curve = nullptr;
static ConstructorHelpers::FObjectFinder<UCurveBase> _DataCurve(TEXT("/Game/NewCurveBase.NewCurveBase"));
if (_DataCurve.Object) {
Curve = (UCurveFloat*)_DataCurve.Object;
}

// テスト表示
UE_LOG(LogTemp, Log, TEXT("Curve:(%.2f) = %f"), 1.08f, Curve->GetFloatValue(1.08f) );


カーブはこんな感じです。適当に曲線でポイントを繋いでいます。

ポップアップ上は 時間1.08の時に値が0.58ですが、実際に取得すると有効桁数が細かくなります。カーブデータのポップアップの有効桁数とは違うので注意が必要の様です。


サウンドデータ(サウンドウェーブ、サウンドキュー)をC++から取得する

se_test というサウンドウェーブデータを取得し再生するテストコードです。

サウンドウェーブ(USoundWave)とサウンドキュー(USoundCue)は、どちらでも 基底クラスのUSoundBase 型でいけます。


.h

UPROPERTY()

USoundBase* Sound_Test;


.cpp

#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h"

// コンストラクタ
static ConstructorHelpers::FObjectFinder< USoundBase > find_sound(TEXT("SoundWave'/Game/Sound/se_test.se_test'"));
if (find_sound.Succeeded()) {
Sound_Test = find_sound.Object;
}

...
// ↑で取得したサウンドデータを再生する
UGameplayStatics::PlaySoundAtLocation(GetWorld(), Sound_Test, GetActorLocation());



まとめ

C++のみでのアセット取り扱いを書きましたが、パッケージ化をする際には参照がされていないアセットは通常含まれませんので、必要に応じて別途設定をしなければなりません。

方法としては


  1. [プロジェクト設定] -> [パッケージング] -> [Packaging] -> [Additional Asset Directories to cook] に対象ディレクトリを追加する。

  2. ゲームインスタンスクラスに参照を追加しておく。

  3. データアセットに参照リストを用意しておく。

などが考えられます。