いんでぃーづ

ゲームいろいろ、いろいろ自由

Unity : PlayMode 中の変更をスクリプトでプレハブに保存、更新する

PrefabUtility 使えば楽勝やろ(鼻ホジー)と思ってたらハマった。

さてどうやろう

普通に考えれば以下3つが必要。

  1. シーン中のインスタンス
  2. インスタンスの元プレハブ
  3. 更新保存するための関数

ここで 2 を 1を元にスクリプトで取得できないか と考えたのがハマりのもとだった。

PrefabUtility にそれっぽいのたくさんあるから...

PlayMode中にシーン内のインスタンスの元プレハブを取得する

結論から言うと できない ぽい。

まず、エディタスクリプト内でこれをやりたい場合は PrefabUtility#GetCorrespondingObjectFromSource を使う。
※前は PrefabUtility#GetPrefabParent だったが移行したようだ

プレイモードに入らずこの関数をシーン内のオブジェクトに対して使えば、ちゃんと元プレハブのパスが取得できる。

が、プレイモードに入った途端に、関数の返す値が null になる。

プレイモード中にGameObject#Instantiate したオブジェクトに対しても、同様にプレハブが取得できない。

何時間か試したが、どうしても取得することができなかった。

PlayMode中のプレハブ関係

どうもプレイモードに入った途端に 既存のプレハブ関係が破棄されているのではないか

まず再生をせずにシーンに配置されているプレハブのインスタンスをインスペクタで見ると、

f:id:sugar_affordance:20190311062216p:plain
エディタモード

プレハブ関係をたどるボタンが表示されている。

次にプレイモードで見る。

f:id:sugar_affordance:20190311062357p:plain
プレイモードでのプレハブのインスタンス

ボタンが消えてしまっている

そしてこのインスタンスをプロジェクトビューにドラッグし、プレハブを作成してみる。

f:id:sugar_affordance:20190311062535p:plain
プレイモード中にプレハブ化

ボタンは復活したがクリックできない

うーむ、謎。
と、ここまで試した段階で、PlayModeで元プレハブを辿るのはあきらめた。

解 : SaveAsPrefabAsset

今回やりたいことは、プレイモードに入る前にインスタントと元プレハブを一対一で取得しておき、PrefabUtility#SaveAsPrefabAssetでプレハブをまるごと置き換えてしまう ことで解決した。プレハブの更新はできるがシーン内の参照がこわれるorz。おそらくシーン内の状態を保存できれば解決するが...

PrefabUtility.ApplyPropertyOverride も試したがよくわからなかった。

詳細は省略するが、エディタスクリプト内で以下のようなかんじでやる。

GameObject instance;  // シーン内のインスタンス
GameObject prefab;    // プロジェクトビュー内のプレハブ

// 元アセットのパスを取得
var prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(pref);

// 上書き
PrefabUtility.SaveAsPrefabAsset(
  instance,
  prefabPath
);

これならプレイモード中でもプレハブの内容を上書きし、他シーンからのプレハブ参照も壊れない。


シーンの更新ができるまで宿題
マニュアル読み返そう...

docs.unity3d.com


“Unity” and Unity logos are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere, and are used under license.


免責事項

当サイトの広告バナー、リンクによって提供される情報、サービス内容について、当サイトは一切の責任を負いません。

また、当サイトの情報を元にユーザ様が不利益を被った場合にも、当サイトは一切の責任を負いません。

すべて自己責任でお願いします。