はじめに
OX ENGINEER STUDIOでクライアントエンジニアをしています、岩永です。
唐突ではありますが、UE5から追加されたMassAIを使ったことはありますでしょうか?
CitySampleを見ると、あれだけの人数をAIで動かすとなるとかなり大掛かりな管理システムとか必要になってくるなとか思ってしまうんですが、MassAIのシステムを使うとものの数時間で同じようなことが出来てしまい、本当にEpicさんには足を向けて寝られません…。
まあ個人の感想はこれぐらいにしておいて、今回はそんなMassAIを使用する時に必須となるFragmentについてお話ししようと思います。
◆MassEntityについての公式ドキュメント
https://dev.epicgames.com/documentation/ja-jp/unreal-engine/mass-entity-in-unreal-engine
◆CitySample
https://www.unrealengine.com/marketplace/ja/product/city-sample
執筆バージョン
Unreal Engine 5.3.2
MassAIについて前提のお話
公式ドキュメントを見ても分かるように、MassAIについてはまだ「Experimental(実験的段階)」となっています。
そのため、今後エンジンのアップデートがかかった際に現在の処理が大きく変わることもありますし、最悪の場合には機能自体がなくなってしまうことも0ではありません。
そのため、本記事の内容も場合によっては使えなくなることもあるため、ご承知おきください。
◆Unreal Engine の実験的、早期アクセス、ベータ機能について
https://www.unrealengine.com/ja/blog/experimental-early-access-and-beta-features-in-unreal-engine
MassAIにおけるFragmentについて
MassAIにおけるFragmentとは、「処理ロジックを持たない、計算で使用する最小のデータ」とのことです。
(※下記のCEDEC講演の資料より言葉をお借りしています)
◆Unreal Engine 5 – Mass Frameworkを用いた群衆AI制御の解説【CEDEC 2022】
https://www.docswell.com/s/EpicGamesJapan/KGPLMK-UE_CEDEC2022_MassFramework#p65
例としていくつかFragmentの中身を見てみます。
● FTransformFragment
USTRUCT()
struct MASSCOMMON_API FTransformFragment : public FMassFragment
{
GENERATED_BODY()
FTransformFragment() = default;
FTransformFragment(const FTransform& InTransform)
: Transform(InTransform)
{}
const FTransform& GetTransform() const { return Transform; }
void SetTransform(const FTransform& InTransform) { Transform = InTransform; }
FTransform& GetMutableTransform() { return Transform; }
protected:
UPROPERTY(Transient)
FTransform Transform;
};
● FMassSimulationLODFragment
USTRUCT()
struct MASSLOD_API FMassSimulationLODFragment : public FMassFragment
{
GENERATED_BODY()
/** Saved closest ViewerDistance */
float ClosestViewerDistanceSq = FLT_MAX;
/**LOD information */
TEnumAsByte<EMassLOD::Type> LOD = EMassLOD::Max;
/** Previous LOD information*/
TEnumAsByte<EMassLOD::Type> PrevLOD = EMassLOD::Max;
};
見てもらうと分かるように、それぞれ「目的毎に必要な情報群」になっているのがFragmentになります。
「FTransformFragment」はTransformの情報を扱うためのFragmentになっているので「Transformの情報」のみ持っていますが、「FMassSimulationLODFragment」は状況に応じたLODタイプの情報を扱うためのFragmentになっているので、「Viewとの距離」や「現在のLODタイプ」、「前回のLODタイプ」といったデータを持っています。
こんな感じで大まかにイメージは持ってもらえたかと思いますが、もしイメージを持ちづらいとかありましたら、単純に「データの構造体」と思ってもらうのが良いかもしれません。
MassAIの使い方
MassAIの使い方については本記事の主旨ではないため省きますが、公式のドキュメントなどで説明されているものを見たり、簡単なチュートリアルについての動画など挙げている方がいらっしゃいますので、検索をしていただきそちらを見てもらうのがいいかと思います。
◆Your First 60 Minutes with Mass (公式ラーニング)
https://dev.epicgames.com/community/learning/tutorials/JXMl/unreal-engine-your-first-60-minutes-with-mass
警告「Fragment was added multiple time」についての結論
先にこの警告について結果をお伝えすると、”無視して大丈夫”です。
(プログラマーとしてエラーはもちろんですが、警告も無くさないと気持ち悪いと思いますが…)
現状、この警告が出ていても問題なく動きますし、内部でもログを出すだけで終わっているようなので大きな問題もないかと思われます。
(今後のアップデートで変わる可能性も勿論ありますが)
ただ、警告で出されているFragmentについて、こちら側で設定したわけでもないのになぜ出るのか?と気になる方もいると思うので、内容を確認していきたいと思います。
警告「Fragment was added multiple time」について
実際に出る警告文としてはこんな内容になります。

この警告について、文字通り「複数回同じFragmentが追加されようとしていますが、追加は1つで大丈夫だよ」と言われているのですが、正直これを見た時の心境としては「複数回も追加した心当たりがないけどナニコレ?」だと思います。
例えば、この警告が出ている状況でのMassEntityConfigはこのような内容になっています
※生成するCharacter側などでは何もTraitsを追加していません

見てもらうと分かるように「Assorted Fragments」のところで二重で追加している訳でもありませんし、ログに出ている「MassAgentMovementSyncTrait」と「MassMovementTrait」では、それぞれでFragmentを追加するような設定項目もありません。
つまりは、こちら側の設定とは別の場所でFragmentの追加処理が行われていることになります。
ではFragmentの追加はどこで行われているのでしょうか?
Fragmentの追加処理
これらFragmentについては、ほとんどが各Traitクラスの「BuildTemplate」という処理で追加されています
例として、今回の警告ログでも出ていた「MassMovementTrait」の「BuildTemplate」の中身を見てみます
void UMassMovementTrait::BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const
{
FMassEntityManager& EntityManager = UE::Mass::Utils::GetEntityManagerChecked(World);
BuildContext.RequireFragment<FAgentRadiusFragment>();
BuildContext.RequireFragment<FTransformFragment>();
// Fragmentの追加処理
BuildContext.AddFragment<FMassVelocityFragment>();
BuildContext.AddFragment<FMassForceFragment>();
//
const FConstSharedStruct MovementFragment = EntityManager.GetOrCreateConstSharedFragment(Movement);
BuildContext.AddConstSharedFragment(MovementFragment);
}
上記の中でコメントで記載してあるように「AddFragment」の処理でFragmentを追加しており、ここでは「FMassVelocityFragment」と「FMassForceFragment」の2つを追加しています
因みに、この「BuildTemplate」という処理はそれぞれのTraitが登録される際に必ず呼ばれるものになります。
//----------------------------------------------------------------------//
// FMassEntityTemplateBuildContext
//----------------------------------------------------------------------//
bool FMassEntityTemplateBuildContext::BuildFromTraits(TConstArrayView<UMassEntityTraitBase*> Traits, const UWorld& World)
{
TraitAddedTypes.Reset();
TraitsDependencies.Reset();
for (const UMassEntityTraitBase* Trait : Traits)
{
check(Trait);
BuildingTrait = Trait;
BuildingTrait->BuildTemplate(*this, World); ← ここで各TraitsのBuildTemplateを呼び出している
}
BuildingTrait = nullptr;
return ValidateBuildContext(World);
}
このように、Fragmentの追加処理はC++側で記載されており、Blueprintからは何を追加されているのか見えません。
各Traitと追加されるFragmentについて
5.3.2時点にはなりますが、私が調べた限りでの追加されるFragmentは以下のようになっています
Traits名 | 追加されるFragment |
---|---|
AgentCapsuleCollisionSync | ・FCapsuleComponentWrapperFragment ・FAgentRadiusFragment ・FTransformFragment(SyncTransformがTrueの場合のみ) |
AgentFeetLocationSync | ・FMassSceneComponentWrapperFragment ・FTransformFragment |
AgentMovementSync | ・FCharacterMovementComponentWrapperFragment ・FMassVelocityFragment |
AgentOrientationSync | |
AssortedFragments | |
Avoidance | ・FMassNavigationEdgesFragment |
CrowdServerRepresentation | ・FMassRepresentationSubsystemSharedFragment ・FMassRepresentationParameters ・FMassVisualizationChunkFragment |
CrowdVisualization | |
CrowdMember | ・FMassCrowdTag ・FMassCrowdLaneTrackingFragment |
DebugVisualization | ・FSimDebugVisFragment ・FMassDebuggableTag ・FDataFragment_DebugVis ・FAgentRadiusFragment ・FTransformFragment |
DEPRECATED_Visualization | ・FMassRepresentationSubsystemSharedFragment ・FMassRepresentationParameters ・FMassVisualizationLODParameters ・FMassVisualizationLODSharedFragment ・FMassRepresentationLODFragment ・FMassVisibilityCulledByDistanceTag ・FMassVisualizationChunkFragment |
LODCollector | ・FMassViewerInfoFragment ・FMassCollectLODViewerInfoTag |
LookAt | ・FMassLookAtFragment ・FMassLookAtTrajectoryFragment |
LookAtTarget | ・FMassLookAtTargetTag ・FTransformFragment |
MassLWIVisualizationTrait | |
MassMovableVisualizationTrait | |
MassStationaryVisualizationTrait | ・FMassStaticRepresentationTag |
Movement | ・FMassVelocityFragment ・FMassForceFragment ・FMassMovementParameters |
NavigationObstacle | ・FMassNavigationObstacleGridCellLocationFragment |
Replication | ・FMassReplicationParameters ・FMassNetworkIDFragment ・FMassReplicatedAgentFragment ・FMassReplicationViewerInfoFragment ・FMassReplicationLODFragment ・FMassReplicationGridCellLocationFragment ・FMassReplicationSharedFragment |
SimpleMovement | ・FTransformFragment ・FMassVelocityFragment ・FMassSimpleMovementTag |
SimulationLOD | ・FMassSimulationLODParameters ・FMassSimulationLODSharedFragment ・FMassSimulationVariableTickFragment ・FMassSimulationVariableTickChunkFragment ・FMassSimulationVariableTickParameters ・FMassSimulationVariableTickSharedFragment |
SmartObjectUser | ・FMassSmartObjectUserFragment |
SmoothOrientation | ・FMassSmoothOrientationParameters |
StateTree | ・FMassStateTreeSharedFragment ・FMassStateTreeInstanceFragment |
Steering | ・FMassMoveTargetFragment ・FMassSteeringFragment ・FMassStandingSteeringFragment ・FMassGhostLocationFragment ・FMassMovingSteeringParameters ・FMassStandingSteeringParameters |
VelocityRandomizer | ・FMassVelocityFragment |
ZoneGraphAnnotation | ・FMassZoneGraphAnnotationFragment ・FMassZoneGraphAnnotationVariableTickChunkFragment |
ZoneGraphNavigation | ・FMassZoneGraphLaneLocationFragment ・FMassZoneGraphPathRequestFragment ・FMassZoneGraphShortPathFragment ・FMassZoneGraphCachedLaneFragment ・FMassZoneGraphNavigationParameters |
この警告を出さないようにするためには?
警告を出さないようにするとしたら、上記の表を見て追加されるFragmentが被らないようにTraitを使っていただくしかありません。
ただし、現時点(5.3.2)ではこちらの警告を出さないようにするのはほぼ不可能に近いのではと思っています。
例えばですが、生成するActorを動かすために必要なTraitsとして「Movment」と「AgentMovementSync」をそれぞれ追加する必要があるのですが、これらを追加すると「FMassVelocityFragment」が被ってしまいます……
このように、希望する動作に対して必須のTraitを設定する場合でも引っ掛かってしまうことがあるので、最初にお伝えしたように現時点ではこちらの警告が出ても気にせずにいて問題はないかと思います。
※私の方での認識や対応の仕方が間違っているかもしれませんので、もし組み方として警告を出さないようにするやり方などあれば、コメント等でご指摘を頂けると有難いです
最後に
今回はMassAIで良く見る「Fragmentの複数追加」警告について見ていきました。
警告文はエラーとは違って動作をさせるには問題なかったりするのでスルーされてしまいがちですが、そのまま実装を進めてしまうとどこかで大きな問題を引き起こしたりするので、警告されている経緯などはしっかりと把握したほうがいいかと思います。
今回のMassAIは「Experimental」ということもあり、警告の内容も問題ないところでしたが、今後ベータや正式リリースとなった際には重要な要素となる可能性もあるので、気になったら中身を確認していきましょう。
ここまで見ていただきありがとうございました!