スクリプトからPrefabを操作する方法です。
Unity2018.3以降の新Prefabワークフローに対応した内容となっています。
Unity2018.2以前はこちらの記事を参照してください。
- Prefabをインスタンス化する
- Prefabを生成/上書きする・Variantを作る
- Prefabを編集して上書き保存する
- UnpackしてインスタンスとPrefabとの接続を切る
- Apply系の操作を行うメソッド一覧
- Revert系の操作を行うメソッド一覧
- インスタンスから対応するPrefabを探す
- インスタンスの一部からインスタンスのルートのGameObjectを得る
- Prefabモードで開く
- 関連
- 参考サイト
Unity2018.3.1f1
※本記事のスクリプトはすべてUnityEditorをusingしています
Prefabをインスタンス化する
Prefabインスタンスをシーンに配置します。
Object assetComponentOrGameObject; // PrefabのコンポーネントやGameObjectを渡すと、 // Prefabのインスタンスをシーンに配置する PrefabUtility.InstantiatePrefab(assetComponentOrGameObject);
GameObject.Instantiate()
を使うとUnpackされた状態でインスタンス化されます。
GameObject prefab;
// Unpackされた状態のインスタンスがシーンに置かれる
GameObject.Instantiate(prefab);
Prefabを生成/上書きする・Variantを作る
Prefabを生成/上書きするには次のようにします。
GameObject gameObject; string assetPath; // Prefabを新規作成・上書きする // ただし既にPrefab化されていてPrefabと違うパスを指定した場合はVariantを作る PrefabUtility.SaveAsPrefabAsset(gameObject, assetPath);
コメントに書いた通り、この関数は少し挙動が複雑です。
まず、まだPrefabが生成されていない場合には新規生成されます。
次に、既にPrefabが存在しているパスを引数に渡すとPrefabを上書きします。
さらに、引数にPrefabのインスタンスを渡し、かつパスがPrefabのものでない場合にはPrefab Variantが作られます。
また、上記の関数ではgameObject
がPrefabと関連付きません。
Prefabを作ってさらに関連付けるためにはSaveAsPrefabAssetAndConnect()
を使います。
GameObject gameObject; string assetPath; // Prefabを作成or上書きして紐づける PrefabUtility.SaveAsPrefabAssetAndConnect(gameObject, assetPath, InteractionMode.AutomatedAction);
最後の引数をInteractionMode.UserAction
にするとUndoが効くようになります。
ユーザが何かのボタンを押すことでPrefabが作れるようなスクリプトの場合にはこっちを使ったほうがよさそうです。
Prefabを編集して上書き保存する
Prefabを編集して保存するにはPrefabを今のシーンにインスタンス化してもいいのですが、
PrefabUtility.LoadPrefabContents()
を使ったほうがスマートです。
このメソッドはPrefabを内部的なシーン上にロードします。
使い方はこんな感じです。Unloadをお忘れなく。
// 内部的なシーンにPrefabをロードする var contentsRoot = PrefabUtility.LoadPrefabContents(prefabPath); // 変更を加える var gameObject = new GameObject(); gameObject.transform.SetParent(contentsRoot.transform); // 保存する PrefabUtility.SaveAsPrefabAsset(contentsRoot, prefabPath); PrefabUtility.UnloadPrefabContents(contentsRoot);
これに関しては以下の記事にも詳しくまとめています。
UnpackしてインスタンスとPrefabとの接続を切る
UnpackしてインスタンスとPrefabとの接続を切ります。
GameObject instanceRoot;
// インスタンスのルートを渡してPrefabとの接続を解除する
PrefabUtility.UnpackPrefabInstance(instanceRoot, PrefabUnpackMode.OutermostRoot, InteractionMode.AutomatedAction);
第二引数をPrefabUnpackMode.OutermostRoot
にするとNestedしている場合に最も近いPrefabとの接続を切ります。
PrefabUnpackMode.Completely
にするとNestedしているすべてのPrefabとの接続を切ります。
また、Prefab生成時と同様に最後の引数をInteractionMode.UserAction
にするとUndoが効くようになります。
Apply系の操作を行うメソッド一覧
Apply系の操作を行うメソッドの一覧です。
メソッド名 | 説明 |
---|---|
ApplyPrefabInstance() | インスタンスで変更されたすべての値をPrefabに反映する |
ApplyObjectOverride() | インスタンスで変更された値を引数のGameObject/コンポーネントの単位でPrefabに反映する |
ApplyPropertyOverride() | インスタンスで変更されたプロパティをPrefabに反映する |
ApplyAddedGameObject() | インスタンスに追加されたGameObjectをPrefabに反映する |
ApplyAddedComponent() | インスタンスに追加されたコンポーネントをPrefabに反映する |
ApplyRemovedComponent() | インスタンスで削除されたコンポーネントをPrefabに反映する |
Revert系の操作を行うメソッド一覧
Revert系の操作を行うメソッドの一覧です。
メソッド名 | 説明 |
---|---|
RevertPrefabInstance() | インスタンスで変更されたすべての値を元に戻す |
RevertObjectOverride() | インスタンスで変更された値を引数のGameObject/コンポーネントの単位で元に戻す |
RevertPropertyOverride() | インスタンスで変更されたプロパティを元に戻す |
RevertAddedGameObject() | インスタンスに追加されたGameObjectを元に戻す |
RevertAddedComponent() | インスタンスに追加されたコンポーネントを元に戻す |
RevertRemovedComponent() | インスタンスで削除されたコンポーネントを元に戻す |
インスタンスから対応するPrefabを探す
インスタンスの持つコンポーネントやGameObjectから、
そのPrefabの中の対応するコンポーネントやGameObjectを取得できます。
Object componentOrGameObject; // インスタンスのコンポーネントやGameObjectを渡すと、 // Prefabの中の対応するコンポーネントやGameObjectを返す Selection.activeObject = PrefabUtility.GetCorrespondingObjectFromOriginalSource(componentOrGameObject);
似たメソッドにPrefabUtility.GetCorrespondingObjectFromSource()
があります。
こちらは一度Prefabと再接続を行うときに使うとのことです(理解できてない)。
インスタンスの一部からインスタンスのルートのGameObjectを得る
インスタンスの持つコンポーネントやGameObjectから、インスタンスのルートにあるGameObjectを取得します。
PrefabUtility.GetOutermostPrefabInstanceRoot()
を使うと、一番外側のルートGameObjectを取得します。
つまり、入れ子になっていた場合には一番親のルートGameObjectが返されます。
Object componentOrGameObject; // Prefabのインスタンスの一部(コンポーネントやGameObject)から // PrefabのインスタンスのルートGameObjectを取得する // Nestedである場合には一番親が返される Selection.activeObject = PrefabUtility.GetOutermostPrefabInstanceRoot(componentOrGameObject);
PrefabUtility.GetOutermostPrefabInstanceRoot()
を使うと、一番近くのルートGameObjectを取得します。
つまり、入れ子になっていた場合には子のルートGameObjectが返されます。
Object componentOrGameObject; // Prefabのインスタンスの一部(コンポーネントやGameObject)から // PrefabのインスタンスのルートGameObjectを取得する // Nestedである場合には子が返される Selection.activeObject = PrefabUtility.GetNearestPrefabInstanceRoot(componentOrGameObject);
Prefabモードで開く
PrefabをPrefabモードで開くにはAssetDatabase.OpenAsset()
を使います。
AssetDatabase.OpenAsset(prefab);
関連
参考サイト
とりあえず使いそうなものだけまとめたので全貌はスクリプトリファレンスをご覧ください。