2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

フォルダ検索&取得

Last updated at Posted at 2024-12-18

この記事はUnreal Engine (UE) Advent Calendar 2024 シリーズ2の19日目の記事です。

以前、wigetでシーケンスのフォルダを操作するという記事を作成しました。
その記事では、『フォルダの追加』『フォルダの削除』『フォルダの探し方』について記載しました。
今回の記事は、『フォルダの取得』について記載していきます。

検証環境

UnrealEngine5.3.2

前知識

今回の記事は、C++ を扱った内容になります。
前回の記事では、MovieSceneFolder型でフォルダを扱うという説明をしました。
このMovieSceneFolder型は、ブループリントで扱う場合には、厄介なクラスになります。
その理由は、以下の点です。

  • 数化できない
  • キャストできない
  • サブクラスを作っても変数化できない

その為、ブループリントで扱う場合は、AddRootFoldertoSequenceノードでフォルダを作成した場合は、戻り値をそのまま使用するしかブループリントでは書けません

これは、追加時は扱いやすいですが、既に存在するフォルダにBindingProxyを入れていく場合には、扱い難いと感じました。

今回は、その部分を取り扱っています。

サンプルコード①

まずは、単純にフォルダを探すコードを作成しました。

//
// ルートフォルダと一つ下の階層を探す
//
UMovieSceneFolder* UMyBlueprintFunctionLibrary::FindFolder(ULevelSequence* LevelSequence, const FString FolderName)
{
	TArray<UMovieSceneFolder*> rootFolders;
	UMovieScene* MovieScene = LevelSequence->GetMovieScene();
	if (!MovieScene)
	{
		return nullptr;
	}
	rootFolders = MovieScene->GetRootFolders();

	for (UMovieSceneFolder* rootFolder : rootFolders)
	{
		FString name = rootFolder->GetFolderName().ToString();
		if (FolderName == name)
		{
			return rootFolder;
		}

		for (UMovieSceneFolder* childFolder : rootFolder->GetChildFolders())
		{
			name = childFolder->GetFolderName().ToString();
			if (FolderName == name)
			{
				return childFolder;
			}
		}
	}

	return nullptr;
}

このサンプルは、見つけた場合は、MovieSceneFolderを戻し、見つけられなかった場合は、nullptrを返します。その為、レベルシーケンスがFolderNameのフォルダを既に持っているかを調べる事にも使えます。

サンプルコード②

次に、見つけられなかった場合は、MovieSceneFolderを新規に作成するようにしました。
サンプルコード①では、見つけられなかった場合は、AddRootFoldertoSequenceノードを実行する必要がありました。

//
// ルートフォルダと一つ下の階層を探す。見つからなければ、新規にフォルダのインスタンスを作成する。
//
UMovieSceneFolder* UMyBlueprintFunctionLibrary::FindFolder_v2(ULevelSequence* LevelSequence, const FString FolderName)
{
	TArray<UMovieSceneFolder*> rootFolders;
	UMovieScene* MovieScene = LevelSequence->GetMovieScene();
	if (!MovieScene)
	{
		return nullptr;
	}
	rootFolders = MovieScene->GetRootFolders();

	for (UMovieSceneFolder* rootFolder : rootFolders)
	{
		FString name = rootFolder->GetFolderName().ToString();
		if (FolderName == name)
		{
			return rootFolder;
		}

		for (UMovieSceneFolder* childFolder : rootFolder->GetChildFolders())
		{
			name = childFolder->GetFolderName().ToString();
			if (FolderName == name)
			{
				return childFolder;
			}
		}
	}

	// フォルダを新規作成
	UMovieSceneFolder* resultFolder = nullptr;

#if WITH_EDITORONLY_DATA

	if (MovieScene)
	{
		MovieScene->Modify();
		resultFolder = NewObject<UMovieSceneFolder>(MovieScene, NAME_None, RF_Transactional);
		resultFolder->SetFolderName(FName(*FolderName));
		MovieScene->AddRootFolder(resultFolder);
	}
#endif

	return resultFolder;
}

説明に『ルートフォルダと一つ下の階層を探す』と書いてあるように、サンプルコード①もサンプルコード②も、『ルートフォルダ』または『ルートフォルダの一つ下の階層』のみしか探しに行きません。
これは、『GetChildFolders』が、そのフォルダが持つ孫階層のフォルダを返さない為です。
これを直す為には、再起関数を使って、階層を遡って探していく必要があります。

サンプルコード③

このサンプルは、再起関数を使って、階層を遡って探していくように改良したものになります。
サンプルコード①を改良したコードになります。

//
// 2階層以降も探しに行く
//
UMovieSceneFolder* UMyBlueprintFunctionLibrary::FindFolder_v3(ULevelSequence* LevelSequence, const FString FolderName)
{
	TArray<UMovieSceneFolder*> rootFolders;
	UMovieScene* MovieScene = LevelSequence->GetMovieScene();
	if (!MovieScene)
	{
		return nullptr;
	}
	rootFolders = MovieScene->GetRootFolders();

	for (UMovieSceneFolder* rootFolder : rootFolders)
	{
		UE_LOG(LogTemp, Warning, TEXT("@@@@ RootFolders:%s"), *rootFolder->GetFolderName().ToString());
		FString name = rootFolder->GetFolderName().ToString();
		if (FolderName == name)
		{
			UE_LOG(LogTemp, Warning, TEXT("@@@@ Match : %s"), *name);
			return rootFolder;
		}

		UMovieSceneFolder* childFolder = SerchChildFolder(rootFolder, FolderName);
		if (childFolder)
		{
			return childFolder;
		}
	}
	return nullptr;
}

//
// 2階層以降も探しに行く為の再起関数
//
UMovieSceneFolder* UMyBlueprintFunctionLibrary::SerchChildFolder(UMovieSceneFolder* SceneFolder, const FString FolderName)
{
	UMovieSceneFolder* resultFolder = nullptr;

	if (SceneFolder)
	{
		for (UMovieSceneFolder* childFolder : SceneFolder->GetChildFolders())
		{
			FString name = childFolder->GetFolderName().ToString(); 
			// UE_LOG(LogTemp, Warning, TEXT("@@@@ SerchChildFolder -> ChildFolders:%s"), *childFolder->GetFolderName().ToString());
			if (FolderName == name)
			{
				return childFolder;
			}
			else
			{
				resultFolder = SerchChildFolder(childFolder, FolderName);
				if (resultFolder)
				{
					return resultFolder;
				}
			}
		}
	}

	return resultFolder;
}

まとめ

エディタの仕様で、UMovieSceneFolderを扱っていて、面倒な箇所が見つかりました。
その為、前回の記事の補足として、今回作成したの記事の対応を行ってみました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?