とっても便利！Unity Prefab Variants のおかげで簡単にいろんなゾンビが作れました！

# 概要

Unity 2018.3 では prefab について３つの新機能があります。

* Prefab Variants
* Nested Prefab
* Prefab モード

今回は、この中の Prefab Variants がとっても便利だったので記事にしたいと思います。
過程で Prefab モード の素晴らしさにも触れます。

対象者は Prefab Variants と Prefab モード の機能に慣れていない人です。
なお2Dです。

# Prefab Variant の使いどころ、効果

Prefab を作っていると、
「プログラムやPrefab構成に共通点が沢山あり、一部の設定だけが違う。」
といった感じのものに出くわします。

これを1つ1つ別の Prefab として用意するのはめんどくさいです。
また、プログラムやPrefab構成に問題があった場合、すべてを修正しなくちゃなりません。

Prefab Variant を使うと、
こういった問題がとても簡単になります。

１つのPrefabを元にして多様なPrefabを作成しておきながら、
元にしたPrefabの変更が、その多様なPrefab達に自動的に反映されるのです。

この記事では、
男ゾンビというPrefabを作成し、
その男ゾンビを元にして、別種のゾンビの Prefabを Prefab Variant として作成します。

最後に男ゾンビに修正を加え、各ゾンビにも反映されることを確認します。


# Prefabの3つの在り方について（最重要点）

Prefab を使っていろんなバリエーションを量産するには、
下記の３つの違いを把握しておくことが **最重要** だと思います。

* Prefab Asset
* Prefab Variant
* Prefab Instance 


**Prefab Asset** は、プロジェクト内に作成される拡張子 「.prefab」 のファイルのことです。
**Prefab Variant** は、 Prefab Asset の参照をもったPrefab Asset です。各パラメータを上書き（override）できます。
**Prefab Instance** は、 シーン上に配置される、Prefab Asset の実態です。

この３つは、Inspectorの見た目や、操作した結果の反映先が少しずつ違います。

自分が今したい編集が、この３つのうちのどの項目に対して行いたいものなのか考えておけば、
強力な力が手に入ると思います。

この記事では違いをご留意いただければと思います。

# Prefab Variant の性質

この記事は Prefab Variant の性質を書くものですが、ここで簡単にまとめておきます。

Prefab Variant は Prefab Asset の参照をもったPrefab Asset です。各パラメータを上書き（override）できます。

当然ながら、Prefab Variantを作るには、参照元となる Prefab Asset が必要です。
参照元は、Baseと書かれたりしてます。

Prefab Variant の性質としては、

* Baseでパラメータを変更すればVariantにも反映されます。
* ただし、Variant側で上書き済みのパラメータであれば反映されません。
* Variantでパラメータを上書きしてもBaseには反映されません。

があげられます。

上記の点を書くと、いろいろ疑問が生まれると思います。

* VariantからBaseに反映したい場合はどうするのか？
* BaseとVariantがどれだけ違ってしまっているのか把握しきれるのか？
* Variantで上書きしてしまったパラメータは、もうBaseの変更を反映できる状態に戻せないのか？
* シーン上で変更してApplyしたら？

この辺りは色々な機能が直観的にサポートしてくれますのでご安心ください。
記事の最後でも改めて触れさせていただきます。

# 実装したものの説明 ( 種類編 )

この記事は Variant を使って楽に実装が出来た、という体験談のため、
実装の流れをトレースします。
そのため、先にどういう仕様を実装をしたのか簡単に説明させてください。

ゾンビを三種類作りました。

![panel1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/34f009d4-de9e-00ba-a771-9601879fb19c.jpeg)

この3種は以下のような違いがあります。

|  | 物理攻撃の方法 | 抱き着き攻撃 | 死亡時に寄生体を吐き出す |
|:------|:-------|:------|:------|:-----|
| 男ゾンビ | 舌 | 〇 | 低確率で吐き出す |
| 女ゾンビ | 舌 | × | 確実に吐き出す |
| 棒ゾンビ  | 木の棒 | × | 吐き出さない |

それぞれの攻撃がどんなものかは、あまり気にしないでください。
また、

* アニメーターコントローラ

も違います。

# 実装したものの説明 ( 動き出し差分編 )

ゾンビは同じ種類であっても色んなアニメーションでスタンバれる（待機できる）ようにします。
プレイヤーが一定以上近づくと、そこから「動き出し」ます。

たとえば

* 「倒れている状態」で待機していて、プレイヤーが近づくと「起き上がって」動き出す
* 「テーブルで食事をしている状態」で待機していて、プレイヤーが近づくと「テーブルから離れて」動き出す
* 「後ろを向いている状態」で待機していて、プレイヤーが近づくと「振り返って」動き出す

![turn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/ed798148-57d6-add1-22b7-c96293a2bae0.gif)

といった感じです（最後のもの以外は、未定だったりしますが）。

つまり、同じ種類のゾンビでも「待機」アニメーション名と戦闘状態へ移行する「動き出し」アニメーション名
を変更できる必要があります。

この差分を「動き出し差分」と呼ぶことにします。

# 最終的にはこうなります

以上の仕様をもとに最終的にはどうなるかを図解しました。
以降はこの図を青写真として実装を進めていく過程になります。

![panel2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/fec32173-6f65-f29f-a99a-2f3a3b7ffd00.jpeg)


男ゾンビをオリジナルの Prefab Asset として作成し、
女ゾンビ、棒ゾンビはこのPrefab Assetを参照した Prefab Variantにします。
また、各種類の中でも動き出しアニメーションに違いがありますが、そこはシーン上に Prefab Instance として配置してから設定を変更します。

# 実装開始。まずは男ゾンビ

## 01. GameObjectを作成

まずはシーン上に新規GameObjectを作成し、男ゾンビとしてセットアップしていきます。

![exp112.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/025eafb8-3705-7fe6-57b3-b5dcdb65f137.png)


ゾンビの挙動は「Villager.cs」というスクリプトで作成しました。
今回この中身に深く触れることはありません。

記事の中にパラメータ名が出てきますが、
あくまで、自作スクリプトの値がどう変わっていくのか、変遷を確認するつもりでご覧ください。

※ Inspector の表示は 「Naughty Attribute」 という Asset で少し見やすくしています。


## 02. GameObjectをPrefab Asset化

Project ウィンドウにドラック&ドロップします。

![panel3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/c1f37bf6-a536-5589-03a7-8667852400e8.jpeg)


Prefab Asset化されました。

![exp4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/0bb5f83a-bd49-d092-46e8-99d6b5c60cf3.png)

この瞬間、Projectウィンドウの中にあるPrefab Assetが本体となり、
ヒエラルキー上にあるのは、このPrefab Assetをソースとした、コピーである、Prefab Instance になっています。

![panel8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/44d985cb-ca53-495b-41ea-c31e2e4a6531.jpeg)

これで男ゾンビは完成です。


# 男ゾンビの動き出し差分を用意してみる

動き出し差分は新しくPrefab Instance を用意して、
その「待機時のアニメーション名」「動き出しアニメーション名」の2か所を変更するだけで表現することにします。
Prefab Asset をシーンにドラッグして Prefab Instance をもう一つ作成します（Villager(1)）

![panel6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/44a0aeb7-1a52-b82a-d09d-cd8b86d095fe.jpeg)


そして、
「待機時のアニメーション名」「動き出しアニメーション名」をそれぞれ 
wait → wait2、 wakeup → wakeup2 に変更します（座標も少し変えておきます）

![exp117.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/83664b44-7054-d431-7405-43fd3b213966.png)


Prefab Asset との 変更点が **太字** になり、また **左に水色のマーカー** がついているのがわかります。

以上で動き出し差分は完成です。

これでこのシーンには2つのPrefab Instance が存在するようになりました。

* Prefab Asset 「Villager」と値が全く同じ　Prefab Instance 「Villager」
* Prefab Asset 「Villager」と２つのアニメーション名が違う、Prefab Instance 「Villager(1)」

Prefab Assetとの変更点はインスペクター上の Override ボタンでもわかります。

![panel7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/c8e7c789-f568-d638-3826-8cc9f643a9dd.jpeg)

このウィンドウ上で対象のコンポーネントをクリックすると、
コピー元との差分が比較できるウィンドウが表示されます。

![exp116.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/59553f52-32bc-fc43-46d9-2f44ec897dbd.png)


Apply All ボタンや、変数名を右クリックして表示されるコンテキストメニューから
Prefab Instanceの変更を Prefab Asset へ反映させることができます。

# Prefab モード について

以降、Prefab の直接的な編集は「Prefabモード」で行います。

## ・Prefabモードを開く

![panel4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/60ce06a1-f642-83d3-ad9f-85ded7b0ec3d.jpeg)

Prefabモードを開くと、シーンビューの表示が変わります。

![panel5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/67ce10d5-3218-3532-25f0-48cc39a315b3.jpeg)


Prefabモードの時にシーンビューやヒエラルキーに表示されているのは、**Prefabステージ** というPrefab編集用の空間の情報です。
なお、普段表示されているのは **Mainステージ** という空間です。

## ・Prefabモードでの編集の保存について

デフォルトのPrefabモードでは Auto Save という機能が有効になっていって、
ヒエラルキーやインスペクターから編集すると、即Prefab Assetが上書きされます。

もしこれがうっとおしい人は下記のチェックを外します。

![exp10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/4f821b06-8096-9541-171d-04ec1b173c00.png)


「Ctrl + S」やメニューから Save を選ばないと修正が反映されなくなります。

## ・動き出し差分のある個所を編集してみる

話を戻して、
今このプロジェクトには３つの男ゾンビがいます。
プロジェクトフォルダの中に

(a). Prefab Asset の「Villager」

という男ゾンビが１つ。

そのほか、シーンのほうに

(b). Prefab Asset の「Villager」と値が全く同じ　Prefab Instance 「Villager」
(c). Prefab Asset の「Villager」と２つのアニメーション名が違う、Prefab Instance 「Villager(1)」

という２つの男ゾンビ。

合計３つです。


ここで、もしPrefab Asset の「Villager」をPrefabモードで開き、
「待機時のアニメーション名」「動き出しアニメーション名」をそれぞれ 
wait → wait3、 wakeout → wakeout3 に変更した場合、
シーン上に配置されている Prefab Instance である「Villager」「Villager(1)」
のそれぞれの値はどうなるでしょうか？

確認してみます。

### (a). Prefab Asset の 「Villager」

![exp118.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/97376b79-79ba-44aa-ef94-ffe62a70a911.png)


### (b), シーン上の Prefab Instance 「Villager」

![exp119.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/6a0731fd-3d87-9cf3-d44d-ee5926b19db4.png)


Prefab Asset の変更が反映されているのがわかります。

### (c). シーン上の Prefab Instance 「Villager(1)」

![exp120.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/b827379e-e416-be07-6f46-671568c3ec7d.png)

Prefab Asset の変更が反映されていないことがわかります。

以上のことから、

**一度 Prefab Instance 側で編集した値は、Prefab Asset 側の変更を受け付けない、** ということがわかります。

# 女ゾンビを作成する。

## ・ Prefab Variantの作成

ようやくですが、Prefab Variant を作成します。
参照元となる Prefab Asset の「Villager」を右クリックして、「Create → Prefab Variant」 を選択します。

![exp27.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/d373478e-9612-e7d2-a44b-724fa7cc8dd7.png)

「Villager Variant」 という名前で作成されるので、ここでは「villager_fe」にリネームしました。

![exp28.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/76810549-b8d2-3535-2e66-68c1ce5c3a87.png)

名前を入力した後、ファイルが保存され、見た目も普通になります。

![exp29.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/8ece349d-cb1d-2d75-be2e-b3c37926abe5.png)

## ・ Prefab Variantの値を変更して女ゾンビにする

Villager_fe を Prefabモード で編集します。

女ゾンビは男ゾンビから下記の点を変更したものです。

* ProjectWindow上での見た目がわかりやすくなるようにSpriteRendererの参照スプライトを変更
* 参照している Animator コントローラを変更
* 抱き着き攻撃をしないので、関連する確率を変更（物理エリア攻撃確率、ホールドエリア物理確率）
* 死亡時に寄生体を確実に吐き出すように確率を変更（特殊死亡率）

これらを変更し女ゾンビの完成です。

![panel15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/9f47f0d0-71d8-7a8c-9e51-f7cd78a81a9b.jpeg)

## ・ 女ゾンビの変更を確認する

序盤に書いた疑問を覚えていますでしょうか？
「BaseとVariantがどれだけ違ってしまっているのか把握しきれるのか？」
こちらの回答ですが、
Prefab Instance の場合と同様、 Override ボタンから変更点を確認することができます。

![panel16.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/e75de710-6373-2144-206a-94807fe2e2c6.jpeg)

どうも下記２つ、似ているように思いませんでしょうか。

* Prefab Asset と Prefab Instance の関係
* Prefab Asset と Prefab Variant の関係

しかしながら、
Prefab Instance と Prefab Variant の場合で「 Apply All 」の部分が微妙に違うのに注目ください。

![panel17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/0404b80c-d829-c86f-39a2-cafc9626a7ca.jpeg)

Prefab Instance の場合には 生成元である Prefab Asset に変更を反映させるものです。
Prefab Variant の場合には、参照元である Prefab Asset に変更を反映させるものです。

似て非なる見た目、似て非なる挙動をとりますが、

* Prefab Asset
* Prefab Variant 
* Prefab Instance 

この３つを把握していれば、ごく普通違いとしてみることができます。


## ・ 女ゾンビを配置する

Prefab Variant も Prefab Asset です。
ですので、 
Prefab Variant もシーン上にドラッグして Prefab Instance を作成することができます。

![panel18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/772a40cd-3ae4-6b06-a89c-303ec5ce47aa.jpeg)


![exp123.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/840ff8c1-329e-74b3-74cc-a8fcaaa1ecf2.png)


## ・ 女ゾンビの動き出し差分を作成する

男ゾンビの時と同様に、シーン上へドラッグ&ドロップをして、もう一つ Prefab Instance を作成し、

* villager_fe (1)

と名付けて、
「待機時のアニメーション名」「動き出しアニメーション名」をそれぞれ 
wake3 → wake4、 wakeout3 → wakeout4 に変更します。

![exp125.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/5394b11d-0215-030b-1e4f-107da0e0230a.png)

これで女ゾンビの動き出し差分も完成しました。

# 棒ゾンビを作成する。

## ・セットアップ

同様にPrefab Variant を作ります。
同様に仕様に合わせてパラメータを変更します。

ただし、男ゾンビ、女ゾンビとは物理攻撃の方法が違うので、当たり判定も修正します。

* 普通のゾンビの場合

![exp130.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/d2b0bb88-5013-7486-059a-1549ee43a0f3.png)

* 棒のゾンビの場合

![exp127.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/3ffb24c3-7328-6136-34d2-cef6face832b.png)

コライダーの名称も「Attack Tongue」→「Attack Log」に変更しました。

![exp131.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/050f1fab-b8e4-e8e5-f322-12bf2313b411.png)

名前の変更も含め、すべて差分が確認できます。

## ・動き出し差分差分

同様の方法で作成できます。

![exp136.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/861ad190-09a4-0a91-5486-d4349d0f7ef6.png)

以上で実装は終わりました。
スクリプトの修正を一切加えることなく、ほとんど一瞬で多様なゾンビが作り出せました。

# 実装を終えて

ここで２点気になるところを解消します。

## 1. Variant の参照元である Prefab Asset の Villager を変更してみる

Villager の Prefab Asset を Prefab モードで開き、
「ZonbieCollision」というGameObjectを作成し、階層構造を変えてしまいます。

![panel19.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/562616c5-9183-48a7-982f-f28068370db0.jpeg)

このとき、女ゾンビ、棒ゾンビのPrefab Asset や シーン上の Prefab Instance のコリジョンはどうなっているでしょうか

* Prefab Asset (女ゾンビ）

![exp141.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/f3cf3422-e1b5-fd9d-6746-57db0f011008.png)

* Prefab Asset (棒ゾンビ）

![exp142.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/6d833a64-4c47-4ccc-4c6b-5d3069d772e5.png)

* Prefab Instance の 女ゾンビ、棒ゾンビ

![exp145.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136196/53b6fa7b-95c3-6bc2-5306-be18ac4f0001.png)




**全て同じように更新がかかっています。**
棒ゾンビに至っては、名前を変えた 「AttackLog」も正しく移動されています。
インスペクタ上の参照も破壊されているといったことはありません。

## 2. 最初に書いた疑問点に回答してみる

【VariantからBaseに反映したい場合はどうするのか？】
Inspector の Override から Apply To Base をすればいい

【BaseとVariantがどれだけ違ってしまっているのか把握しきれるのか？】
Inspector の Override の UI から 変更があるコンポーネントはすべて表示され、差分も確認できる。
怖がる必要は全くない。

【Variantで変更済みにしてしまったパラメータは、もうBaseの変更を反映できる状態に戻せないのか？】

「Apply」もしくは「Revert」をすることで、

* Apply の場合には、Base の Prefab Asset に Variant の値を反映させる形で
* Revert の場合には、 Variant側で Prefab Asset の値を反映させる形で

Variant と Base は共通のパラメータを持つ形に戻ります。

以降は Base の変更が Variant に適応される形に戻ります。

【 シーン上で変更してApplyしたら？】

Prefab Instance の変更は Prefab Asset に反映されます。
Prefab モード で、対象となる Prefab Asset を操作したときと同じ結果を生むと考えればいいです。

# まとめ

最新のPrefab ワークフローはとてもシンプルで強力だと思います。
何の工夫もなく、簡単に多様なゾンビを作ることができ、運用ミスで設定がおかしくなるような不安もありません。

これまでは、
Prefab Asset をシーンにおいてPrefab Instance 化して編集し、Apply ボタンで Prefabへ変更を反映させていました。

今後はこの作業はあまりしないと思います。

というのも、編集をするさいに、

* Prefab Asset
* Prefab Variant
* Prefab Instance

のどれを編集するのが適切か？

を常に自らへ問いかけると、
そういった運用は減るのではないかと思うからです。