関連ブログ
- [UE5] 元の位置に戻るカメラの実装 2024.12.18UE
- [UE5]難易度変更に対応したシューティングゲームを作ってみよう 2024.12.11UE
- [UE5] インタラクト可能なモノの量産に役立つBPを作ってみよう 2024.12.04UE
CATEGORY
2022.12.28UE5UE/ C++UE/ Editor拡張
執筆バージョン: Unreal Engine 5.1 |
皆さんこんにちは。エンジニアの森です
今回の記事では以下のように、Map 型変数にいくらでもデフォルト値のキーを追加できるようにします
Map 型とは整数や文字列などハッシュ可能な値をキーにして任意の値と紐づけできる型のことです
Setという重複を許さない配列も用意されています
BP上では以下のようにDetailsウィンドウから型選択できます
ドキュメントはこちらです
ドキュメントにも書かれていることですが、いざ使ってみようと思うと以下のようなエラーが出ます
今日はエンジンを改造することでこの問題に対処します
まずは、このエラーが出ている場所を探します
エディター上にメッセージが表示されているので、これをソースコード上で検索しましょう
場所が特定できました
「{Engine格納場所}\Engine\Source\Editor\PropertyEditor\Private\PropertyHandleImpl.cpp」です
エンジンバージョンは「5.1.0-0+++UE5+Release-5.1」を使用しています
ソースコードの変更内容は以下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
FPropertyAccess::Result FPropertyValueImpl::ImportText( const TArray& InObjects, const TArray& InValues, FPropertyNode* InPropertyNode, EPropertyValueSetFlags::Type Flags ) { // 略 FScriptSetHelper SetHelper(SetProperty, ValueBaseAddress); if (SetHelper.HasElement(Cur.BaseAddress, NewValue) && (Flags & EPropertyValueSetFlags::InteractiveChange) == 0) { // Duplicate element in the set ShowInvalidOperationError(LOCTEXT("DuplicateSetElement", "Duplicate elements are not allowed in Set properties.")); //return FPropertyAccess::Fail; ←削除 } // 略 FScriptMapHelper MapHelper(MapProperty, ValueBaseAddress); if (MapHelper.HasKey(Cur.BaseAddress, NewValue) && (Flags & EPropertyValueSetFlags::InteractiveChange) == 0) { // Duplicate key in the map ShowInvalidOperationError(LOCTEXT("DuplicateMapKey", "Duplicate keys are not allowed in Map properties.")); //return FPropertyAccess::Fail; ←削除 } return Result; } FPropertyAccess::Result FPropertyHandleSet::AddItem() { FPropertyAccess::Result Result = FPropertyAccess::Fail; if (IsEditable()) { /* 削除 if (!HasDefaultElement()) { Implementation->AddChild(); Result = FPropertyAccess::Success; } else { Implementation->ShowInvalidOperationError(LOCTEXT("DuplicateSetElement_Add", "Cannot add a new element to the set while an element with the default value exists")); } */ // 挿入↓ if (HasDefaultElement()) { Implementation->ShowInvalidOperationError(LOCTEXT("DuplicateSetElement_Add", "Cannot add a new element to the set while an element with the default value exists")); } Implementation->AddChild(); Result = FPropertyAccess::Success; // 挿入↑ } return Result; } FPropertyAccess::Result FPropertyHandleMap::AddItem() { FPropertyAccess::Result Result = FPropertyAccess::Fail; if (IsEditable()) { /* 削除 if ( !HasDefaultKey() ) { Implementation->AddChild(); Result = FPropertyAccess::Success; } else { Implementation->ShowInvalidOperationError(LOCTEXT("DuplicateMapKey_Add", "Cannot add a new key to the map while a key with the default value exists")); } */ // 挿入↓ if (HasDefaultKey()) { Implementation->ShowInvalidOperationError(LOCTEXT("DuplicateMapKey_Add", "Cannot add a new key to the map while a key with the default value exists")); } Implementation->AddChild(); Result = FPropertyAccess::Success; // 挿入↑ } return Result; } |
ガードしている部分を無くしました
警告を表示している部分のはそのまま残しているので、警告ウィンドウは出てきます
結果を確認しましょう↓
同じキーを持つ値をいくらでも追加できるようなりました
ランタイムでもキーを取得できます↓
キーを探すときは、エディター上で一番下に見えている値が取得できるようです
これで完了です
UE4.27 でこの部分のソースコードは同じでした(同じ改造もできました)
エンジン改造は自己責任でお願いします
ありがとうございました
マップのキーに使えるHash可能な型とは、ここにあるようにoperator==とGetTypeHash関数をサポートしている型のことです
記事のおまけとしてコード例を置いておきます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// FTestKeyType を TMap のキーに使える USTRUCT(BlueprintType, MinimalAPI) struct FTestKeyType { GENERATED_BODY() public: UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 A; UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 B; FTestKeyType(int32 InA, int32 InB) :A(InA), B(InB) {}; FTestKeyType() : A(-1), B(-1) {}; friend bool operator==(const FTestKeyType& first, const FTestKeyType& second) { return (first.ID == second.ID) && (first.GenderType == second.GenderType); } friend FORCEINLINE uint32 GetTypeHash(const FTestKeyType& Other) { return GetTypeHash((int64(Other.A) << 32) | int64(Other.B)); } }; |