本記事はUnreal Engine (UE)のカレンダー | Advent Calendar 2023 - Qiita シリーズ 5の 1日目の記事です
はじめに
ホグワーツレガシーの開発者による講演「Collision Data in UE5: Practical Tips for Managing Collision Settings & Queries(Unreal Engine 5での衝突データ: 衝突設定とクエリの管理に関する実用的なアドバイス)」にて、「エンジン改造してCollision PresetのCustomを禁止するのはいいぞ」という内容がありましたが、具体的にどうすればいいのかは説明がなかったので…調べて記事にしました!
動いてる様子
アメリカのUnrealFestでホグワーツレガシーの開発者が紹介していた、コリジョン設定のCustom無効化&検索対応ができた!…エンジン改造必須だけど...
— おかず (@pafuhana1213) 2023年12月8日
アドカレのネタは多分これになります#UE5 #UE5Study pic.twitter.com/g52S3gHv3O
なぜCustomを禁止にすると良いのか?など講演の内容に関しては下記記事でまとめてるのでどうぞ!
(Customが混在してるとバグの温床になるし、調査もしづらい的な理由です)
pafuhana1213.hatenablog.com
実現方法
Customを選択不可能に
Engine\Source\Editor\DetailCustomizations\Private\BodyInstanceCustomization.cpp
void FBodyInstanceCustomization::OnCollisionProfileChanged( TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo, IDetailGroup* CollisionGroup ) { // if it's set from code, we did that on purpose if (SelectInfo != ESelectInfo::Direct) { // add if( NewSelection == CollisionProfileComboList[GetCustomIndex()]) { return; } // ...
Customをグレーアウトに
TSharedRef<SWidget> FBodyInstanceCustomization::MakeCollisionProfileComboWidget(TSharedPtr<FString> InItem) { FString ProfileMessage; FCollisionResponseTemplate ProfileData; if (CollisionProfile->GetProfileTemplate(FName(**InItem), ProfileData)) { ProfileMessage = ProfileData.HelpMessage; } return SNew(STextBlock) .Text(FText::FromString(*InItem)) // add .IsEnabled(!InItem->Equals(TEXT("Custom..."))) // .ToolTipText(FText::FromString(ProfileMessage)) .Font(IDetailLayoutBuilder::GetDetailFont()); }
Customをリストから消しちゃう
既にCustomを使用しているプロジェクトだと何らかの問題起きそう
void FBodyInstanceCustomization::RefreshCollisionProfiles() { int32 NumProfiles = CollisionProfile->GetNumOfProfiles(); bool bCanUseDefaultCollision = CanUseDefaultCollision(); // first create profile combo list CollisionProfileComboList.Empty(NumProfiles + (bCanUseDefaultCollision ? 2 : 1)); //If we can use default collision we'll add a "Default" option // first one is default one if(bCanUseDefaultCollision) { CollisionProfileComboList.Add(MakeShareable(new FString(TEXT("Default")))); } // comment out //CollisionProfileComboList.Add(MakeShareable(new FString(TEXT("Custom...")))); //
以降は上記コード変更に対しての簡単な補足
補足
「Customを選択不可能に」の補足
FBodyInstanceCustomization::OnCollisionProfileChanged は Collision Presetのリストから選択した際に呼ばれる処理なので、Customだったら処理スキップしちゃえという強引実装です。ちなみに、!ProfileData.bCanModify だとDefaultもグレーアウトされちゃいました。残念
あ、FBodyInstanceCustomization::AddCollisionCategory の 後半に上記関数を登録している処理があります
SAssignNew(CollsionProfileComboBox, SComboBox< TSharedPtr<FString> >) .OptionsSource(&CollisionProfileComboList) .OnGenerateWidget(this, &FBodyInstanceCustomization::MakeCollisionProfileComboWidget) .OnSelectionChanged(this, &FBodyInstanceCustomization::OnCollisionProfileChanged, &CollisionGroup) .OnComboBoxOpening(this, &FBodyInstanceCustomization::OnCollisionProfileComboOpening) .InitiallySelectedItem(DisplayName) .Content() [ SNew(STextBlock) .Text(this, &FBodyInstanceCustomization::GetCollisionProfileComboBoxContent) .Font(IDetailLayoutBuilder::GetDetailFont()) .ToolTipText(this, &FBodyInstanceCustomization::GetCollisionProfileComboBoxToolTip) ]
「Customをグレーアウトに」の補足
↑のコードにある通り、MakeCollisionProfileComboWidgetはComboBox内の各選択項目の構築処理です。
.OnGenerateWidget(this, &FBodyInstanceCustomization::MakeCollisionProfileComboWidget)
で、CustomだったらEnableを falseにしてグレーアウトしちゃえという強引実装です
「Customをリストから消しちゃう」の補足
FBodyInstanceCustomization::RefreshCollisionProfiles()では ComboBoxで表示するCollision Presetの配列(TArray TSharedPtr
もっとダイナミックに拡張したいぜ!という方は、FBodyInstanceCustomization::AddCollisionCategory後半のSlate構築処理を弄っていくことになるかと思います!ちなみに構築時のコールスタックはこんな感じ
FBodyInstanceCustomization::AddCollisionCategory(TSharedRef<IPropertyHandle,1>,IDetailChildrenBuilder &,IPropertyTypeCustomizationUtils &) BodyInstanceCustomization.cpp:128 FBodyInstanceCustomization::CustomizeChildren(TSharedRef<IPropertyHandle,1>,IDetailChildrenBuilder &,IPropertyTypeCustomizationUtils &) BodyInstanceCustomization.cpp:267 FDetailPropertyRow::OnItemNodeInitialized(TSharedRef<FDetailCategoryImpl,1>,const TAttribute<bool> &,TSharedPtr<IDetailGroup,1>) DetailPropertyRow.cpp:323 FDetailItemNode::InitPropertyEditor() DetailItemNode.cpp:154 FDetailItemNode::Initialize() DetailItemNode.cpp:45 FDetailCategoryImpl::GenerateNodesFromCustomizations(const TArray<FDetailLayoutCustomization,TSizedDefaultAllocator<32> > &,TArray<TSharedRef<FDetailTreeNode,1>,TSizedDefaultAllocator<32> > &) DetailCategoryBuilderImpl.cpp:1001 FDetailCategoryImpl::GenerateChildrenForSingleLayout(const FDetailLayout &,const TArray<FDetailLayoutCustomization,TSizedDefaultAllocator<32> > &,TArray<TSharedRef<FDetailTreeNode,1>,TSizedDefaultAllocator<32> > &) DetailCategoryBuilderImpl.cpp:1023 FDetailCategoryImpl::GenerateChildrenForLayouts() DetailCategoryBuilderImpl.cpp:1044 FDetailCategoryImpl::GenerateLayout() DetailCategoryBuilderImpl.cpp:1210 FDetailLayoutBuilderImpl::BuildCategories(const TMap<FName,TSharedPtr<FDetailCategoryImpl,1>,FDefaultSetAllocator,TDefaultMapHashableKeyFuncs<FName,TSharedPtr<FDetailCategoryImpl,1>,0> > &,TArray<TSharedRef<FDetailCategoryImpl,1>,TSizedDefaultAllocator<32> > &,TArray<TSharedRef<FDetailCategoryImpl,1>,TSizedDefaultAllocator<32> > &) DetailLayoutBuilderImpl.cpp:316 FDetailLayoutBuilderImpl::GenerateDetailLayout() DetailLayoutBuilderImpl.cpp:456 SDetailsViewBase::UpdateSinglePropertyMap(TSharedPtr<FComplexPropertyNode,1>,FDetailLayoutData &,bool) SDetailsViewBase.cpp:665 SDetailsViewBase::UpdatePropertyMaps() SDetailsViewBase.cpp:608 ...
Unreal Engine (UE) Advent Calendar 2023、既にたくさん記事が公開されてるので是非見てみてください!
明日以降の記事もすごく楽しみですー!
qiita.com
おしまい