ゲーム作りが大好きな人のブログ

ゲームを作るのが大好きな人のブログ。UE4とBlender、MAYA(LT)、3DCoatを使用しています!

【UE4】【C++】EditDefaultsOnlyを使う際の注意点

C++でレベルを管理するにあたりUPROPERTYのEditDefaultsOnlyを多用しますが、公式マニュアルや内部ソースコードコメントだけだと勘違いを起こしやすいので、実際に動作させてみて、その結果をまとめてみました。

※ 検証バージョンUE4.27.1
※ 2021/11/24追記:最後に例外パターンを追記

EditDefaultsOnlyはレベルに保存される

UPROPERTY(EditDefaultsOnly,BlueprintReadWrite)
bool bEditDefaultsOnly = false;

レベルに配置されたアクターの「詳細」パネルに表示されないEditDefaultsOnlyですが、このパラメータは初期値から変更された際にレベルに保存されてしまいます

これは設計としては当然の形と思いますが、利用者側は勘違いする可能性があります。なにせパラメータが見えないので「保存されていないだろう」と思い込むからです。

「表示されてないのにどうやって変更するのさ」と思うかもしれませんが、これは多岐に渡って方法があります。簡単な例でいうと、他のアクターが自身のEditDefaultsOnlyの変数をコンストラクションスクリプトなどで書き換えに来るパターンです。BlueprintReadWriteが付いているとBlueprintからも書き換えられる可能性があります。このパターンで書き換えられるとエディターからは変更が確認できないので重いバグに繋がる可能性があります

EditDefaultsOnlyでレベルに保存されないようにするには

UPROPERTY(Transient, EditDefaultsOnly, BlueprintReadWrite)
bool bEditDefaultsOnly = false;

UPROPERTYの中にTransientを付けるだけです。これでレベルに保存されなくなります。

Transientも勘違いしやすい

Transientは「一時的」という意味で、機能面をざっくりと説明すると

  • BPアセットで初期値として変更した場合は保存される
  • レベルに配置→そのレベル内のオブジェクトで値が変更されてもレベルに保存されない

といった感じになります。つまりアセットが持つ初期値は保存されますが、レベル配置した物への変更分は適用されないという意味になります。

最後に。ソースコードとしてまとめました

DuplicateTransientとNonPIEDuplicateTransientを含めています。

//	Transientはレベル上に配置して値を変更しても保存はされない。
//	アセットの規定値が最優先される。
UPROPERTY(Transient, EditAnywhere)
bool bTransient = false;

//	EditDefaultsOnlyは気をつけたい。
//	レベルに配置して、そのレベル上で値が変更されると保存されてしまう。
//	EditDefaultsOnlyは「詳細」からパラメータが見えないので危険性が高い。
UPROPERTY(EditDefaultsOnly)
bool bEditDefaultsOnly = false;

//	上のを回避する版。
//	EditDefaultsOnlyで不意の値変更を避ける場合はTransientを付けること。
UPROPERTY(Transient, EditDefaultsOnly)
bool bTransientEditDefaultsOnly = false;

//	DuplicateTransient
//	Editorワールドでの複製時、PIE実行時にアセットの基底値に初期化される。
UPROPERTY(DuplicateTransient, EditAnywhere)
bool bDuplicateTransient = false;

//	NonPIEDuplicateTransient
//	Editorワールドでの複製時にアセットの基底値に初期化される。
//	PIE実行時には値はレベルで設定した値が使われる。
UPROPERTY(NonPIEDuplicateTransient, EditAnywhere)
bool bNonPIEDuplicateTransient = false;

(2021/11/24追記)後日、例外パターンを発見・・・

  1. C++でComponentを作る(この時、Transientの変数を作る)
  2. BPでActor継承のアセット作る
  3. ②で作ったBPアセットに①のComponentをBPエディターで付ける
  4. ComponentにあるTransientの変数を変更して保存する

このケースはComponentのTransient変数の値が保存されない事が分かりました(Editorを再起動すると元に戻っている)。こ、これはBlueprint側からスポーンしているからそうなるのか?(汗