最初に
この記事はBPを用いたアセットをロードしてSpawnするところまで記事にしたものとなります。間違いや更に良い方法があった場合にはそっとTwitter( @ろっさむ )やコメント、修正リクエストなどでお知らせ頂けるととても有難いです。
作業環境
記事内で使用する作業環境は以下の通りとなります。
- Unreal Engine:4.23.1
- Visual Studio:Community 2017 or Community 2017 for Mac or Enterprise 2019
前提として知っておきたいデメリット
まず、同期的なロードを扱うと、ロード処理中はメインスレッドを占有してしまうため、プレイヤーから見るとUIも処理も止まってゲーム画面がフリーズしているように見えたりかくついて見えます。
そのため、ミニマムなアセットロードを行う処理であれば問題ありませんが、重いアセットのロードを一気に行うとユーザー体験を損ねる可能性があるので注意が必要です。この場合は非同期なロードを行う必要があります。
実装方法
①LoadObjectを使用する
LoadObject
を用いた場合、中身的にはConstructorHelpers::FObjectFinder
と同等です(実際FObjectFinder
ではLoadObject
を用いてロードしてます)。
文字列を直接書き込んで参照することができますが、クック時に読み込まれないことがあります。その場合Asset Managerが有効となります。
void ACPP_StartGameMode::BeginPlay()
{
Super::BeginPlay();
FVector EnemyPosition = FVector(100, 1424.302734, 91.790405);
// BPをc++から呼び出す際は末尾に_cをつける
// マテリアルなどの場合であれば_cは不必要
UClass* EnemyCharacterBP = LoadObject<UClass>(this, TEXT("Class'/Game/MyEnemy/Enemy_Meca.Enemy_Meca_c'"));
if (EnemyCharacterBP)
{
AActor* EnemyCharacter = GetWorld()->SpawnActor<AActor>(EnemyCharacterBP, EnemyPosition, FRotator::ZeroRotator);
}
}
②LoadSynchronousを使用する
ここではFSoftObjectPath
でアセットの文字列を指します。LoadSynchronous
で実際のアセットロードを行います。こちらはパスを変数にして扱いやすいかと思われます。
void ACPP_StartGameMode::BeginPlay()
{
Super::BeginPlay();
EnemyCharacterPath = "/Game/Developers/mio/Contents/MyEnemy/Enemy_Meca.Enemy_Meca_c";
FVector EnemyPosition = FVector(100, 1424.302734, 91.790405);
TSubclassOf<class AActor> EnemyCharacterBP = TSoftClassPtr<AActor>(FSoftObjectPath(*EnemyCharacterPath)).LoadSynchronous();
if (EnemyCharacterBP)
{
AActor* EnemyCharacter = GetWorld()->SpawnActor<AActor>(EnemyCharacterBP, EnemyPosition, FRotator::ZeroRotator);
}
}