【Unity】新規ゲームのUI開発で気をつけた39のTips後編

本記事は[サムザップ #2 AdventCalendar 2020](https://qiita.com/advent-calendar/2020/sumzap2) の12/22の記事です。
昨日の記事は@tsain17さんの『[普段のタスク管理にNotionを使ってみた](https://qiita.com/tsain17/items/27d950622a592e077f64)』でした


株式会社サムザップでUnityエンジニアをしている大庭[@ohbashunsuke](https://twitter.com/ohbashunsuke)です。

前年に引き続き今年もサムザップ社員エンジニア**全員参加**のアドベントカレンダーが始まりました。

[昨年のアドベントカレンダー](https://qiita.com/advent-calendar/2019/sumzap1)でもUnity関連のTips記事を執筆しましたが、今年も引き続きUnityにまつわるTipsを執筆していこうと思います。

- [開発初期に暇を持て余しているUnityエンジニアができる42のTips前編](https://www.shibuya24.info/entry/sumzap_adventcal20191211)
- [開発初期に暇を持て余しているUnityエンジニアができる42のTips後編](https://www.shibuya24.info/entry/sumzap_adventcal20191224)

## 本Tipsの前提

普段僕が関わることの多い**「スケジュールは潤沢ではない中〜大規模スマホゲーム開発」**を前提としたTipsになっております。ここ数年新規ゲーム開発の立ち上げに携わることが多く、そこで得たUI開発の知見を詰め込んでみた感じです。一つでも皆様の為になる話があれば幸いです。

先日執筆した[【Unity】新規ゲームのUI開発で気をつけた39のTips](https://qiita.com/ohbashunsuke/items/0570234362e2e45c0011)の後編です。

※ここからが本題です。

## ■UIレギュレーション編

UIレギュレーションとはUIデザイナーが考え抜いたUIの規則や決まりを指しています。

- ダイアログの決定ボタンは、**必ず**この座標に配置する
- このプロジェクトでは赤色とは#ff0000ではなく、少しくすんだ赤色を**必ず**使用する
- 文字のサイズは24, 20, 16の3種類から**必ず**使用する

例えば上記のような決まり事が**UIレギュレーション**です。
UIレギュレーションを決めることで統一されたデザインになります。
統一されたデザインになって何が良いかと言うと**情報が正しく伝達される**ようになります。

### ※極端な例

以下のUI例ではクエストだけボタンが大きくなっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/562fe4d7-8ce9-a499-9b80-1729ac1769b9.png" width=550 />

クエストを目立たせたいという意図であれば良いかもしれませんが、そうではないのであれば、それは**「正しい情報が伝達できていない」**という事になります。
※あくまで極端な例です

デザインは装飾的な部分に目がいきがちですが重要なのは **「情報を整理する事」**です。
情報が整理され、正しく情報が伝達できていなければそれはデザインされているとは言えないのです。

UIレギュレーションを作り、それを守ることで不要な情報やノイズをカットし、伝えたい情報を伝えやすくします。

### 前置きをまとめると

UIレギュレーションとは**「正しく情報を伝達する」**ための超重要なファクターです。

集団開発をすると、各メンバーの情報に差が出てくるため大抵UIレギュレーションは崩れていきます。

UIレギュレーション編は**「UIレギュレーションをいかに保守していくか」**という視点のTipsになります。

## Tips.18 UIレギュレーションを理解する日々の思考

UIレギュレーションを保守するためにはプロジェクトメンバー全員とは言いませんが、せめてUnityエンジニア側が理解しておくべきです。

### UIを組み込むフローについて

UIデザイナーからUnityエンジニアに対してUIの**画像パーツ素材**と**完成図**のキャプチャを渡されてUIを実装していく事になると思いますが、UIデザイナーからの一方的な伝達フローではUIレギュレーションは壊れやすいです。

### 渡されたデザインの意図を汲み取る

各パーツの配置座標、色、サイズなど実装する前に、完成図のデザインが語っているものを汲み取る事が大事です。

- 今回実装した色が前回と微妙に違うのはなぜか？
- テキストのサイズがいつもより小さいのはなぜか？
- やたらUIパーツの配置間隔が詰まっているがなぜか？

この**「なぜ」**を繰り返してUIデザイナーと対話します。

繰り返しになりますが**「デザインとは情報整理」**です。
全ての内容に説明が出来なければいけません。

ある意味デザインはプログラムと同じです。UIのロジックに矛盾があればそれは先々で不具合の原因となる可能性が潜みます。

与えられたデザインを理解進めながら実装することで、UIレギュレーションの認識が合っていきます。

### デザインの意味に興味を持つ

ただ与えられたものを与えられた通りに実装するという事は比較的誰にでも出来ます。一歩先に行くためにはUIデザイナーが考えている視点と同じ場所に立って思考することです。

通常業務の中でデザインに興味を持ち、何を語っているのかを思考することでUIレギュレーションが守られていく環境が作られていくと考えています。

**※また偉そうな事を書いてしまいましたが、お許しください**


## Tips.19 UIレギュレーションに関わるデータを実装箇所毎に直書きしない

例えばこのようなソースコードがあったとします。

```cs
text.color = new Color32(218, 79, 100, 255);
```

これがユニークでオンリーワンなUIであれば良いのですが、UIレギュレーションで決まっている色の場合は問題が起きます。

### UIレギュレーションに変更が入った時に抜け漏れる

開発序盤はUIレギュレーションは**よく変わります**。
変わってしまうとレギュレーションではないのですが、様々な事情から変わることになります。仕方ないことなのです。

変わってしまうと先のカラー設定を検索して全て書き直す必要が出てきて非常に手間なのとオペミスで抜け漏れの可能性がでてきます。

特に**Prefabやシーンに保存されている場合 (ソースコードからはたどり着けない場所)** に記述がある場合は事故りやすいです。

### UIレギュレーション定義クラスを用意する

```cs
public static class ColorDefine
{
    // UIレギュレーションの赤
    public static readonly Color32 Red = new Color32(218, 79, 100, 255);
    
    // UIレギュレーションの青
    public static readonly Color32 Red = new Color32(88, 92, 100, 255);
}
```

上記のような定義ファイルを用意します。

```cs
text.color = ColorDefine.Red;
```
※使用例

カラーに変更があったとしても`ColorDefineクラス`を調整するだけで修正作業は完了します。
色以外だと、スケールアニメーションのスケール値、配置マージンなどがあります。

複数箇所で使用されるルール(UIレギュレーション)となり得る値を何度も記述していることに気付いたら立ち止まって定義する事を検討してはいかがでしょうか。

またそのタイミングでUIデザイナーと対話して確認するのも良いでしょう。

## Tips.20 UIコンポーネントからレギュレーションを指定できるようにする

**「Tips.19 UIレギュレーションに関わるデータを実装箇所毎に直書きしない」**と関連して、UIコンポーネントからUIレギュレーションを設定できるようにしておくと保守性が高まります。

以下のキャプチャは、とあるプロジェクト専用のテキストコンポーネントです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/48084b5f-042a-f238-d2d8-ed5ae170d96a.png" width=500 />

カラーを定義したEnum ColorTypeでカラーを設定できるようにしておきます。
わざわざ色をカラーピッカーから設定する必要は無いのです。

```cs
[SerializeField] ColorType _colorType;
[SerializeField] Text _text;

void OnValidate()
{
    // ColorTypeからUIレギュレーションカラーを取得するColorResolverを作っておく
    _text.color = ColorResolver.Resolve(_colorType);
}
```
エディットモード中の調整を想定しています。インスペクタの値が変更された時に実行されるOnValidateメソッド内でカラーを適用出来るようにしておきます。

これによりエンジニア外のメンバーが調整をしやすくなるという副次的な効果もあります。
このようにUIレギュレーション守るための楽な方法はエンジニア側からどんどん提供していきましょう。

### 余談:開発序盤のColorPresetLibrary利用はあまりオススメしない

独自のカラーテーブルを定義できるColorPresetLibraryを使ってUIレギュレーションを保守するというやり方もあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/ba9fa5f1-3be4-e725-9f49-17ae51ae79ff.png" width=250 />

ただ、こちらは開発終盤でなければ上手く回らないです。

あくまでカラーのプロパティをセットしやすくするだけで**UIレギュレーションの変更には対応できない**からです。カラーの変更が入った場合、該当箇所全てを変更する必要がありますので、レギュレーションが固まりきらない開発序盤、中盤、終盤手前までは使えない印象です。

開発終盤手前まで使っていないのであれば、それ以降も使う必要はないかなというのが僕の中の答えです。
(色を二重管理する事にもなりますし)


## Tips.21 UIパーツの命名規則に振る舞いをキーワードとして入れると破綻する

若干UIレギュレーションを守る話と毛色が変わりますが紹介させてください。

**「UIパーツの命名規則」**はUIレギュレーションを守る上で非常に重要です。

開発を進めていくとUIパーツの種類が増えていきます。増えていく度に名前をつけるわけですが、この名前を適当につけていると後で大きな手戻り、または事故に繋がります。

以下はよくある話です。

1. 最初は**「OK」**の時しか使わないボタンだったので、OKButtonと名付けた
2. 開発が進むうちに、OKボタンは**「キャンセル時」**にも使うようになりった
3. 名前と使い方に矛盾が出てきたのでリネームしようとした
4. しかしすでに大量に様々な場所で使用されていて影響範囲が大きく困った

ここでのポイントは使い方が変わるようなものに対して振る舞いをキーワードとして使った事です。[^1]

[^1]: 開発終盤の場合は大丈夫かもしれません

また以下のようなパターンもあります。

1. UIレギュレーション的に大中小の3種類のサイズのボタンを必ず使っていくと決めた
1. LargeButton、MiddleButton、SmallButtonとそれぞれ名付けた
1. 開発が進むうちに大と中の間のサイズがどうしても必要になったので、仕方なくMiddleButton2というものを追加した
1. MiddleButton2とMiddleButtonの間のサイズが必要になった
1. MiddleButton2_1と名付けた

同じような例で色も同様です。

1. 最初赤色、青色のボタンを使っていました
2. RedButton、BlueButtonと名付けました
3. カラーのレギュレーション変更でピンクと緑ボタンにデザイン変更が入った
3. ※割愛 もう分かりますよね？

このようにプロジェクトに後からジョインした人が「ん？」と疑問を持ちそうな不可解な名前のUIパーツが量産されていきます。

繰り返しになりますが、**「UIパーツの命名規則」**はUIレギュレーションを守る上で非常に重要です。

命名によって無駄なコミュケーションコストが掛かり、UIレギュレーションが崩れていきます。

### 対策 : 振る舞いや見た目で命名しない

`OKButton`や`LargeButton`と名付けたいところですが、僕の場合はButton_0_0、Button_0_1と機械的につけるようにしています。最初の数字がボタンのサイズ、後ろの数字が種類という感じで分けてあげると、先程の矛盾は解決できます。数字じゃなくアルファベットでも良いでしょう。

振る舞いや見た目を名前にしないことが重要です。

数字やアルファベットは逆に覚えづらいし混乱するという声もおっしゃるとおりです。
しかし**「矛盾しているキーワードの方が現場は混乱する」**というのが僕の中の答えです。


## Tips.22 UIレギュレーションを守るための自動生成

- 開発中盤UIレギュレーションが決まってきた
- UIの量産をそろそろ始めないといけない

こういうタイミングでUIの自動生成を試みると良いかも知れません。

- ダイアログ
- 画面
- 各種UIコンポーネント(ボタン、リスト、ゲージ、テキストなど)

上記3種はゲームのUI開発する上で量産対象になります。
雛形となるPrefabを簡単に作れるようにしておくと良いでしょう。

- 雛形Prefabの作成
- 必須クラスのAddComponent
- 各種設定

こういった内容の自動生成をしておくと、量産時の開発効率に効いてくるのでオススメです。

特にUIの量産タイミングで人も増員することがあります。新規のメンバーはUIレギュレーションの理解が浅いので、このような自動生成の仕組みを使うことがUIレギュレーションの保守に繋がります。


## Tips.23 UIレイアウトの自動化

先の**「Tips.22 UIレギュレーションを守るための自動生成」**と一部重複しますが、自動レイアウトも量産前にトライしておきたいところです。

ここで言う自動レイアウトとはUIレギュレーションで決まっている且つ多数存在するレイアウトの自動化です。

### 例 : ダイアログのボタンのパターン

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/4f23bc53-0fa0-5bad-959f-0b31b6719c18.png" width=400 />

- ボタンは必ずダイアログの下部の先端から60pxの位置に配置
- ボタンを２つ配置する場合は左側がx:-130f、右側がx:130fへ
- ボタンが1つの場合はx:0へ配置

ダイアログコンポーネントに以下のようなボタン配置の設定を追加します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/32f10270-41d2-a16c-ab60-67b36d76e165.png" width=450 />

ボタンの配置処理としては以下のようなイメージ。

```cs
private const float BottomMarginY = 60f;
private const float SidePositionX = 130f;

// ボタンの配置処理。EditMode中はOnValidateの中から呼ばれる。
protected void ApplyButtonPosition(PositionType positionType, RectTransform target)
{
    target.anchorMin = new Vector2(0.5f, 0);
    target.anchorMax = new Vector2(0.5f, 0);

    switch (positionType)
    {
        // センター配置
        case PositionType.BottomCenter:
            target.anchoredPosition = new Vector2(0, BottomMarginY);
            break;
        // 左側配置
        case PositionType.BottomLeft:
            target.anchoredPosition = new Vector2(-SidePositionX, BottomMarginY);
            break;
        // 右側配置
        case PositionType.BottomRight:
            target.anchoredPosition = new Vector2(SidePositionX, BottomMarginY);
            break;
        // 座標フリー(例外パターンが発生した時の対応)
        case PositionType.BottomFree:
            // ※SetAnchoredPositionYは独自の拡張メソッド
            target.SetAnchoredPositionY(BottomMarginY);
            break;
    }
}
```

このような感じで、**確実にUIレギュレーションとして決まっているもの**はソースコードを変更する事なくインスペクタの設定で済ませた方がミスは減ります。

また非エンジニアと分業ポイントにもなります。



## Tips.24 UIレギュレーションに矛盾に気付いた時は早めに見直す

ここまでUIレギュレーションを保守する工夫Tipsを紹介してきましたが、それでも様々な都合、仕様変更で矛盾が発生してしまう時があります。

特に手を動かして実装しているUnityエンジニアは真っ先に気付いてしまう事があります。

### 極端な例

「戻るボタンで画面遷移した時はダイアログを開かない」というUIレギュレーションがあったとします。
**「あれ？？ここダイアログだと次の画面で戻る押した時どうすりゃいいんだ？？」**みたいなことにUnityエンジニアが気付いてしまいました。

いくつか解決手段があります。

- UIレギュレーションを変更する
- 仕様を見直す
- 戻り先が不自然になるが放置する

こんな時どうするか？

Tipsタイトルの通り企画職、デザイナーを巻き込んで**「早めに見直す」**です。

前述の通りUIレギュレーションの矛盾というのは、とりあえず動作はしますが**「正しい情報が伝わっていない」**ため不具合に近いものだと考えています。

プロジェクトの進捗や納期にも関係してくるため一概に言えませんが、開発中に発覚したのであればリリースまでに正しい状態に修正しておきたい所です。


## ■UIアセットワークフロー編

ここで言うUIアセットとはアプリ同梱、アセットバンドルどちらもスコープ内で、以下のものを指します。基本的にUnityエンジニアよりクリエーターが作成する事が多いのでは無いでしょうか。

- テクスチャ
- AnimationClip
- 各種UIPrefab
- ScriptableObject

非エンジニアのUnity作業におけるトラブルが起きづらいワークフローの構築についてのTipsです。

## Tips.25 テクスチャインポータの自動化

スマホゲーム開発の場合、テクスチャはPVRTC、ASTC、ETC2といった圧縮テクスチャフォーマットに変換する事になります。

毎度手動で設定するのはオペミスの元です。
ファイル命名、またはディレクトリ毎などでルールを設け、`AssetPostprocessor`と`AssetImporter`を使って自動で圧縮テクスチャに変換をする事をオススメします。

## Tips.26 アセットビルドワークフロー

アセットのアップロードから実機確認までの流れを非エンジニア完結にすることで、お互いが変に干渉することなく同時並行で開発出来るようになります。

現在携わっているプロジェクトではクリエーターに以下の作業をやってもらっています。

- Unityプロジェクトにアセットの追加、更新
- SourceTreeを使ったGit操作(ブランチを切る、プル、コミット、プッシュ)
- GitHub上でプルリクエスト(マージはUnityエンジニアがやる)
- ジェンキンスからアセットのビルドジョブ実行

ビルドが成功してアセットがサーバーにアップロードされたらSlackに通知が飛ぶので、それを見て実機で確認してもらいます。

アセットビルドワークフローをほぼ完全に非エンジニア完結にすることで、エンジニアは開発をゴリゴリ進める裏側でクリエーターは粛々とアセットのブラッシュアップ進めることが出来て効率的に開発が進みます。

## Tips.27 アセットチェッカー

アセットビルドワークフローが非エンジニア完結していて効率的と謳いましたが、デメリットもあります。
どうしても手作業な部分があるため、オペミスが発生することです。

オペミス自体は仕方ないとして、それを検出しないと問題が起きます。10~20くらいのアセット数であれば手作業で取り除けますが、1000、10000といった大量のアセットを前にすると手作業でやるには厳しいです。

そこでアセットのバリデーションを充実させます。

- テクスチャのサイズが違う
- アセットバンドル名がルール外
- ストーリーのスクリプト文法ミス
- ファイル名がルール外
- 使用すべきシェーダではない
- ScriptableObjectの設定がおかしい

正しく設定されているかどうか自動でチェックが走る仕組みを作っておくと良いでしょう。

今やっているプロジェクトだと、1日1回全アセットに対してチェック処理のジェンキンスジョブが走ります。その結果はSlackに通知されるようになっており、各担当者がそれぞれ修正し、正しいアセットの状態を保持するようにしています。

副次的な効果としてエンジニアにわざわざ聞かなくても不具合の内容がなんとなく分かる箇所が増えて無駄なコミュニケーションが減ったことです。各担当者が自走出来る環境は大事だなと思いました。

このようなバリデーションツールの開発はあまり作業工数として見積もられない部分だと思いますが、ゲーム運用のディフェンス部分として強化しておくと良いでしょう。


## ■UI担当Unityエンジニアマインド編



## Tips.28 Unityを共通言語にして職種を越えた連携を進める

与えられた「UIの設計」を実装すればゲームとしての要件は満たせますが良いUIになるかどうかは分かりません。

「本当はこういう風に演出させたいけど、難しそうだよな？」

「こういう表現したいけどUnityの事が分からないから何も言えない」

このような非エンジニアの心の声って意外とあります。

その人がUnityの事を知っていれば、その作業が大変なのかそうではないのか、可能なのか不可能なのかが分かるようになり、よりモノづくりのコミュニケーションが活発になるでしょう。

ゲームをより良くするためには組織的にUnityの知識量をアップして、モノづくりの視点を上げていく事が大事だと考えています。

ではどうやって非エンジニアに対してUnityの知識量を上げていくかというと、**「実際にUnityを使った業務をやってもらう」**です。

もちろん人を選ぶかも知れませんが、ただただクリエーター向けUnity勉強会を開くだけではその場だけの知識で終わってしまいます。

僕が実践しているのは**UIデザイナーにUnityを触れる環境を意識して提供**することです。

例えば、自分が担当になっている開発チケットにUI調整部分が入っているのであれば、それをUIデザイナーに割り振ります。最初はUnityの使い方から、Prefabの保存方法、Gitの操作といった基本的な部分を時間をかけて教える必要はあります。


しかし時間が取られるのも最初だけで、数をこなすことでUIデザイナーにとって通常業務となり、最近はあまり口を出すことはありません。

ある程度UIデザイナー側のリソースとやる気が無いと成り立たないため、文字で書いているほど簡単ではないとは思いますが、サムザップをモノづくり組織として強くするために実践している事の紹介でした。


## Tips.29 少々のことなら自分でPhotoshopを使って編集できるようになる

UI開発する上でデザイン待機時間は発生します。

1. UIデザイナーがデザインを仕上げる
2. UIデザイナーがデザインパーツを切り出す
3. UIデザイナーがUnityエンジニアにパーツを納品する
4. UnityエンジニアがUIを組み込んでいく
5. 実機で評価

このような開発手順になっている事が多いのではないでしょうか。[^2]

[^2]: プロジェクトによってはUIデザイナーがUnity上でレイアウトもするといったこともあるかもしれません。

UIを組み込んだ後、実機を触って評価をすると大抵修正が発生します。

静止画状態では気づかなかった事がなぜか実機で触ってみると気付いてしまう不思議現象は10年開発してきてなくなることはありません。
やっぱり実機で触ってみないと本質部分にはヒトは気づけ無いのかなと。。。

本題はそこではありません。
修正が発生するのはしょうがないのです。その修正を待たないとエンジニアの作業が止まるというのが問題です。

1. 実機で評価して修正発生
1. **UIデザイナーが修正デザインを仕上げる**
1. **UIデザイナーがデザインパーツを切り出す**
1. **UIデザイナーがUnityエンジニアにパーツを納品する**
1. UnityエンジニアがUIを組み込んでいく

修正が発生したら、上記2~4の間Unityエンジニアは待機することになります。
1回修正してOKが出れば良いのですがね...

開発フェーズが序盤でUIレギュレーションやテイストも何も決まっていない状態では、このやり取りは無駄と考えています。

そろそろ2021年、**待ってるだけのUnityエンジニアは古い**のです。[^3]

[^3]: 嘘ですが半分本気です

もちろん根本から覆すデザイン修正の場合は待機することになりますが、

- ボタンのサイズを少し変える
- パーツの色を変えてみる
- 画像を差し替える
- UIを傾ける

などといった軽微な修正であればUnityエンジニア側で対応した方が格段に早いです。

最終的なプロダクトクオリティに持っていくのはデザイナーの仕事になってきますが、開発序盤ではUnityエンジニアもUIデザイナーの一員という気持ちで取り組むとよいと考えています。そこまで高いクオリティは求められません。それよりも**早く形にすること**が大事です。

そのために画像編集ツール(PhotoshopやXD)を使いこなせておくと良いでしょう。

「仕様やデザインが出来てないから、Unityエンジニアは何も作業が出来ないんです〜」
という方は以前僕が執筆した以下の記事を読んでもえるとよいかと思います。

- [開発初期に暇を持て余しているUnityエンジニアができる42のTips前編](https://www.shibuya24.info/entry/sumzap_adventcal20191211)
- [開発初期に暇を持て余しているUnityエンジニアができる42のTips後編](https://www.shibuya24.info/entry/sumzap_adventcal20191224)


<!-- Photoshopテクニックのスライドを完成させて公開する。間に合わず。 -->



## ■UI開発Tipsおまけ編

ここからは細かいテクニックやUI開発Tipsをサクサク紹介していきます。

## Tips.30 似たようなNestedPrefabが大量に生成されないような工夫

NestedPrefabはとても便利なんですが、大量に増えるとそれはそれで管理が大変です。特に同じようなUIパーツが大量に発生してしまいます。ちゃんと命名してあげないと使う側が混乱する元です。

そのために出来る限り同じようなパーツをNestedPrefab化させない工夫なのですが、ランタイム中にプログラム側から値をセットするという方法です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/1e29355f-18e7-1c29-5493-1dd1b5c61a0a.png" width=500 />

上図のように4つボタンがあった場合を例にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/afef6040-8dc5-8313-7b8e-970086935c20.png)
NestedPrefabのバリアントを作ってこのように4つ作る事になります。

ただしボタン同士の差分は**テキストのみ**です。
ただテキストの文字列が違うだけなのにNestedPrefabが4つあるのです。

### 差分部分をプログラムからセット

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/091e84cd-8166-41e0-04fb-0939fb7cf501.png" width=500 />

このようにボタン自体は4つ配置しますが、それはテキスト部分はプログラムからランタイム中にセットします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/4912e1dc-a7ca-d95f-80dd-40005f05e727.png)

こうする事で4つのPrefabが1つに減ったことになります。時と場合によっては上記のテクニックが使えるのではないでしょうか。

## Tips.31 UI Environmentの設定

`Project Settings > Editor > Prefab Editing Environments`はUnity2018.3でNestedPrefabが導入されたタイミングで追加された設定です。
<img src="https://i.gyazo.com/ec403bfa548e8e2d2e6ac7bc916ed56d.png" width=500 />
ご存知の通りuGUIはCanvasコンポーネント配下でないと正常に表示されません。

`UI Environment`にプロジェクトで使用するCanvasやカメラを配置したシーンを設定しておくと、プレファブモード時にそのシーンを使用してくれます。 

とりあえずuGUIを使う場合は**設定必須**です。


## Tips.32 よく使う拡張メソッドを用意しておく

これはUI開発に限った話ではないですが記述コード量を減らして開発効率をあげようという話です。
UI開発時はRectTransformクラスを多用するため、以下のようなメソッドを用意しておくと良いでしょう。

```cs
public static void SetSizeDeltaX(this RectTransform r, float value){/*処理は割愛*/}

public static void SetSizeDeltaY(this RectTransform r, float value){/*処理は割愛*/}

public static void SetAnchoredPositionX(this RectTransform r, float x){/*処理は割愛*/}

public static void SetAnchoredPositionY(this RectTransform r, float y){/*処理は割愛*/}
```

RectTransform意外だとImageやRawImageなど。

## Tips.33 SRDebuggerを導入したデバッグ機能の開発効率化

実際にその場面にいかないと確認できないUIの動作テストは工夫をしないと無駄に開発に時間がかかります。
開発環境にデバッグメニューを用意してボタン1つで動作確認できるようにしておくのですが、そのデバッグメニューを作るのが結構コストになります。

それをサポートするのがSRDebuggerです。

```cs
[Category("画面遷移")]
[SROptions.DisplayNameAttribute("ホーム")]
[SROptions.SortAttribute(0)]
public void ToHome(){/*遷移処理*/}

[Category("画面遷移")]
[SROptions.DisplayNameAttribute("クエスト")]
[SROptions.SortAttribute(1)]
public void ToQuest(){/*遷移処理*/}

[Category("画面遷移")]
[SROptions.DisplayNameAttribute("キャラ")]
[SROptions.SortAttribute(2)]
public void ToChara(){/*遷移処理*/}

[Category("画面遷移")]
[SROptions.DisplayNameAttribute("イベント")]
[SROptions.SortAttribute(3)]
public void ToEvent(){/*遷移処理*/}
```

以下のようなデバッグメニューが簡単に作れます。
すぐに画面遷移できるデバッグボタンを配置しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/18c0a4c6-deb4-6b37-47cc-6c9a6a0f0604.png" width=450 />




```cs
[Category("パラメータ")]
[SROptions.DisplayNameAttribute("体力")]
[SROptions.SortAttribute(0)]
public int Hp { get; set; } = 100;

[Category("パラメータ")]
[SROptions.DisplayNameAttribute("レベル")]
[SROptions.SortAttribute(1)]
public int Lv { get; set; } = 1;
```

また上記のようなコードを書けばパラメータを変更するUIも簡単に作れます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/9d9af260-d3f8-933e-012f-f119eab3873b.png" width=350 />

開発にデバッグメニューは欠かせません。ただデバッグメニューの見た目を作るのもそこそこ工数がかかります、その辺りをこのアセットで吸収してみるとよいのではないでしょうか。

### SRDebuggerはデバッグメニュー以外の機能も充実

- デバイス情報
- コンソール機能
- CPUプロファイラ
- バグレポート

これらの機能もくっついて非常に開発中はとてもお世話になっています。デバッグメニューも大事ですが、スマホ実機上でDebug.Logなどで出力したログが確認できるのが良いです。

とてもオススメです。
<a href="https://assetstore.unity.com/packages/tools/gui/srdebugger-console-tools-on-device-27688?aid=1100lNUQ">SRDebugger - Console & Tools On-Device</a>

## Tips.34 AnimationEventから実行されるメソッドはわかりやすい名前にする

AnimationClipに設定するAnimationEventを使う場合、イベントに紐づくメソッドを定義するわけですが、ソースコードをエディタ読む際に参照が辿れません。

他の開発メンバーに未使用メソッドと判断されて消されかねないので、AnimationEventで実行されるメソッドであることが分かるような名前にするのが良いでしょう。

```cs
public void OnReceiveAnimationEventHogehoge(){/*処理*/}
```
**※例です**

## Tips.35 カメラを分ける場合、カメラに何も写っていなければレンダリングしない設計

- ダイアログ
- シーン内のコンテンツ
- 3Dモデル

などなど

UI開発中、実装の関係上カメラを分けた場合は、何も写していない場合は、パフォーマンスの観点からカメラコンポーネントごと非アクティブにすると良いでしょう。

## Tips.36 Buttonコンポーネントはそのまま使わない

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/645113ae-ae03-3590-2fd2-91b51b420bc0.png" width=350 />

Unityにはボタンのための`Buttonコンポーネント`があります。
ただし実際のプロジェクトでそのまま使う事は無いです。

理由としては、各種インタラクション**(タップダウン、非アクティブな状態など)**に対するアニメーションは各ゲームで違うため`Buttonコンポーネント`をそのまま使わず、各ゲームごとでよく使うボタンを独自に実装する事になります。

## Tips.37 開発序盤だからといってButtonコンポーネントを使わない

**「早く形にするのが大事」**と言いましたが、明らかに手戻りになるような作業は避けたい所です。ボタンを速攻で作らなければならないので、Buttonコンポーネントで至るところで実装したとします。

開発中盤になって、Buttonコンポーネントでは表現できない、要件に合わないので拡張しないといけない状況が出たらどうなるでしょうか。

- Buttonコンポーネントを削除して
- 代わりのコンポーネントをくっつける
- 該当箇所のソースコードを書き換える

このような無駄作業が大量に発生します。見落としてしまうかも知れません。
開発序盤こそスピード感をもって作らなければなりませんが、明らかに手戻りそうな事を選択しないようにしておきたいものです。


## Tips.38 インスペクタからイベントを登録しない

インスペクタからのイベント登録は一見便利そうですが、僕的には使うタイミングが思いつかないというのが現状です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/deb7cb3d-227c-c048-5bc3-a35debd59b71.png" width=450 />

理由としては3点あります。

1. 処理をソースコードから追えなくなる
1. 使用ケースに出会わない
1. オペミスを防ぎづらい

### 1.処理をソースコードから追えなくなる

これは前述の**「Tips.34 AnimationEventから実行されるメソッドはわかりやすい名前にする」**のくだりと同様で、ソースコード内に参照関係がないので処理を追う事が難しくなります。

困るのはバグが起きた時です。**「ボタンを押した時に不具合が起きる」**という報告を受けた際、Unityエンジニアはまずソースコードを調査しますが、ソースコードをいくら漁っても該当の処理にたどり着きません。

なぜなら実行元がソースコードに書かれていないからです。
コメントアウトなどで補足は書いてあったとしても気づきづらい状況なのは間違いないです。


### 2.使用ケースに出会わない

1. 予めUnityエンジニア側でメソッドを用意しておく
1. ボタンの実行先をインスペクタから非エンジニアに実装してもらう

開発フローとしては、このような流れになるのかなとは思うのですが、こういう状況に出会ったことがなく自ら作りたいとも思わない感じです。

理由としては、ボタンの実行先を非エンジニアが決めるという状況にそもそも出会ったことがありません。
ソースコードを変更することなく調整でき、コンパイルが走らないため、すぐに結果を確認できて便利というメリットがあるのかもしれません。ただ、くり返すようですが、僕が今まで携わった開発環境でこれがベストプラクティスになりそうな場面はありませんでした。


### 3. オペミスを防ぎづらい

非エンジニアがインスペクタからボタンの実行先をセットする際、ファイルの差分が出るとしたらシーンファイルやPrefabです。

GitHubなどでレビューするわけですが、yaml形式の文字列**(シーン、Prefabの中身)**を眺めても理解するのは困難です。正しくイベントがセットされていれば良いのですが、何か挙動がおかしい時、例えばセットする処理を間違えていた場合はソースコードからは原因を特定することは難しいです。

UnityEditorから該当のPrefabやシーン内のインスペクタを調査するという非効率な作業が発生します。このようなオペミスを防ぐためのバリデーションだったり、レビュー時にインスペクタのキャプチャを貼ってもらったりして工夫する必要があるかもしれません。

以上3点の理由から**よっぽどの事**がない限りはインスペクタからイベントを登録することは無いというのが僕の中の回答です。


## Tips.39 開発終盤まで細かいUIレイアウトする必要は無い

最後のTipsになります。

今までの経験上、**UIデザインはゲーム開発中3~5回は変わります**(大きな変更から小さな変更まで含めます)。

1発で仕上がることはありません。

それはプログラムも同じでしょう。
僕は天才ではないので初期設計で全てを考慮して書き直しが無いということは無いです。

プロジェクトが進む毎に「こうした方が良いだろう、ああした方が良いだろう」と試行錯誤を重ねていく上でクオリティが上がっていきます。

デザインも同様で、序盤・中盤には大枠は決まるかもしれませんが、最終的に細かい部分は**終盤の終盤の終盤**に決まっていきます。

ということは、終盤までUIレイアウトを厳密に合わせる必要は無いということです。

デザインをかじったディレクターやプロデューサーが仮にいたとして、序盤中盤のゲームの状態をチェックした際に、ピクセル単位のUIパーツのずれを指摘するという事があるかもしれません。

**「そのタイミングでピクセル単位のUI合わせに価値があるのか」**を真剣に議論した方が良いと思います。

繰り返しになりますが、プロジェクトが進むと結局差し替え、作り直しになるため開発効率的にも50~70%くらいの精度でポンポンと配置して作業スピードを上げた方がプロジェクトのためだと僕は思っています。

## 最後に

いかがだったでしょうか。
直近僕が新規ゲームのUI開発で気をつけた事を紹介してきました。
前編後編合わせて結構な文字量になってしまいましたが、何か1つでも皆様の開発の役に立てばと思います。

それでは良いお年を。

※前編はコチラ[【Unity】新規ゲームのUI開発で気をつけた39のTips前編](https://qiita.com/ohbashunsuke/items/0570234362e2e45c0011)


明日は @kazuhiro1128 さんの『[UnityでAR Foundationでユニティちゃんを表示してみた](https://qiita.com/kazuhiro1128/items/a561e494dfc7dca26aed)』です。