本記事は、サムザップ Advent Calendar 2019 #1 の12/24の記事です。

前編はコチラ
2020年版のアドベントカレンダー

株式会社サムザップでUnityエンジニアをしているオオバ@ohbashunsukeです。
グラフィックデザイナー、Flashデベロッパーを経て、現在はUnityエンジニアでスマホゲームを作っています。Unity歴は6年くらいです。
今までコマンドバトル、ピンボール、麻雀などを作ってきました。

これから紹介していく内容は、開発初期後回しにされがちな、でも初期にやっておいた方が良いことばかりです。
オオバはUnityエンジニアとしてプロジェクトを進める上で以下の事を重要視しています。

この思想も取り入れた形でリストアップしました。

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

本記事の導入

新規ゲームプロジェクトがスタートし、あなたはUnityエンジニアとして参画する事になったと想定します。しかし、ゲーム仕様はまだ真っ白な状態で、計画しているモック開発の要件も決まっていません。

「あ〜仕様も決まってないし、やる事がなくて暇だな〜」

って、

んな事ぁない!!

仕様が無くてもやる事はいくらでもあります。

今回のタイトルを見て「42Tips!?多すぎじゃない・・・!?」と思ったあなた!ぜひ読んでみてください。
今まで新規開発に携わる事の多かったオオバが思いつく「仕様がなくてもUnityエンジニアが開発序盤にやれる事」をツラツラ紹介していきます。

本記事は開発初期に暇を持て余しているUnityエンジニアができる42のTipsの後編です。

UI系

19.UI解像度を決める(UIを作り出す前に必ずやる)

uGUIを使用する場合は、CanvasScalerに設定するReference Resolutionの値を決めるという話です。
デザイナーの元データにも影響があるので、UIを作り出す前に決めておく必要があります。

解像度毎のパターンを作り、対象となる実機何点かで実際に確認して決めれば良いと思います。
その際、スマホと解像度比率の大きく違うタブレット端末での見え方も注意すると良いでしょう。

20.共通UIパーツを共通のPrefabにする

UI画面にはよく各画面同じようなパーツが出てきます。

などなど。

これらをそれぞれの画面で新規で作成するのは無駄なので、デザインがまだ仮の状態の時から共通のPrefabとして使い、デザインが仕上がってきたら、該当するPrefabの中身を差し替えていくのが良いでしょう。ただし、開発が進む中で無理やり使い続けている感が出てくる場合は、ケースバイケースで作り直した方が良いです。

21.ダイアログなどのシーンをまたいで使用するものはDontDestroyOnload領域へ

以下のようなシーン間、または各シーンで共通して使用したいもの、シーンをまたいで削除されたくないものはDontDestroyOnload(gameObject);として、シーン遷移時にメモリから破棄されないようにします。

22.ダイアログシステム作成

ダイアログは大抵どのようなゲームでも必要になるので、先に取り掛かります。

暫定要件

などなど。

この中でも「ダイアログは重なって表示できるようにする」は、デザイン次第ではやりたくないという意見も出る場合がありますが、その時に考えて一旦動くものを作って体感を確認しながら進めるのがオオバは好きです。経験的にもその方がプロジェクトはより早く前に進みます。

 // hogehogeとメッセージを表示させるダイアログを表示する  
 DialogManager.Instance.Open(new AlertDialog(){  
    message = "hogehoge",  
    okCallback = ()=> Debug.Log("OK"),  
    cancelCallback = ()=> Debug.Log("cancel")  
});  

上記のような感じでダイアログを呼べるように一旦実装しています。

23.UI用のCanvas共通化処理

UI用のCanvas、CanvasScalerの設定はプロジェクトで共通設定になる事が多いです。
それを毎度毎度設定するのは非効率のため、以下のような自動化できるコンポーネントを作っておきます。

 using UnityEngine;  
 using UnityEngine.UI;  

 ///  
 /// Canvas初期化  
 ///  
 [ExecuteInEditMode]  
 [DisallowMultipleComponent]  
 public class UICanvasInitializer : MonoBehaviour  
 {
     private CanvasScaler _scaler;  

     void OnEnable()  
     {
         Execute();  
     }
 #if UNITY_EDITOR  
     void OnValidate()  
     {
         Execute();  
     }
 #endif  
     void Reset()  
     {
         Execute();  
     }

     void Execute()  
     {
         if (_scaler == null)  
         {
             _scaler = GetComponent();  
         }

   // 内容は適宜  
         _scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;  
         _scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;  
         _scaler.referenceResolution = new Vector2(1920f, 1080f);  
     }
 }

このような共通コンポーネントを作っておくと、修正が入った時に対応しやすいです。

24.UI階層構造のルールを決める

デザインによって大きく変わる可能性がありますが、大抵以下のような構成になるので一旦これで作ってしまいます。

各シーン

DontDestroyOnLoad領域

25.タップ・スワイプエフェクトを実装しておく

スマホゲームを作る場合、必ずと言っていいほどタップした時やスワイプした時のエフェクトが必要になります。
優先度的には後でもよい判断をされるかもしれませんが、先に実装しておく事をおすすめします。

タップ・スワイプエフェクトは最前面に表示されなくてはいけません。
後から実装すると、UIの階層関係を構築する際に見落としてしまって、手戻りをしてしまう可能性があります。
オオバは表示階層に関わるものに関してはできるだけ優先的に実装しておく事にしています。

また、先に実装し、prefab化しておけば、クリエーターにブラッシュアップをお願いするのも楽です。

26.UI Environmentの設定

Prefab Editing Environmentsは、Unity2018.3からNestedPrefabが導入され追加された設定です。

開発初期に暇を持て余しているUnityエンジニアができる42のTips後編_0

必ず設定しておいたほうが良いのは UI Environmentです。
uGUI関連のPrefabをプレファブモードで編集する際、uGUIはCanvas配下に存在しないと表示が崩れます。

UI EnvironmentにCanvasやカメラを配置したシーンを設定しておくとプレファブモード時にそのシーンを使用してくれます。
NestedPrefabを使用する際は必須設定なので序盤に忘れないように設定しておきたいです。

ちなみに、UI Environmentに設定するシーン内のCanvasは23.UI用のCanvas共通化処理で紹介した設定を適用すると良いでしょう。

27.iPhoneXセーフエリア対応

セーフエリア対応はデザインの序盤に思想を決めて動けていないと、後々大きな手戻りが発生する可能性があります。
デザイナーとしっかり相談して、意志を統一していきたいところです。

また、iPhoneX系の実機で日々確認するのも大事です。

28.UIカラー設定コンポーネントを作っておく

デザインが進んでいくとキーとなるカラーが決まってきます。
uGUIのパーツを予め白色で作成しておき、プログラムで色を重ねて作成する場合があります。

その際、指定カラーをUnity上でひとつひとつセットしていくのはとても無駄な作業です。
少しでも楽をするための以下のようなコンポーネントを用意しておきます。

 ///  
 /// 決まったカラーをセットする  
 ///  
 public class GraphicColorSetter : MonoBehaviour  
 {
     [SerializeField] private ColorType _colorType;  
     [SerializeField] private Graphic _graphic;  
     // trueにすると実行時に指定色を反映する  
     [SerializeField] private bool _isRuntimeApply;  

     void OnEnable()  
     {
      if (isRuntimeApply)  
             ApplyColor();  
     }

     public void SetColorType(ColorType type)  
     {
         _colorType = type;  
         ApplyColor();  
     }

     void ApplyColor()  
     {
         // ColorResolverにColorTypeに対する色を定義して返却できるようにしておく  
         _graphic.color = ColorResolver.Resolve(_colorType);  
     }

 #if UNITY_EDITOR  
     void OnValidate()  
     {
         if (Application.isPlaying == false)  
         {
             if (_graphic == null)  
             {
                 _graphic = GetComponent();  
             }
             else  
             {
                 ApplyColor();  
             }

             if (_graphic == null)  
             {
                 Debug.LogError("Graphic is not Found", this);  
             }
         }
     }
 #endif  
 }

開発初期に暇を持て余しているUnityエンジニアができる42のTips後編_1

このようにプルダウンでカラーを指定し反映する事ができるので効率的ですし、非エンジニアでも対応可能になります。
また開発序盤中盤はカラーの変更はザラにありますが、その反映もソースコードを変更するだけで対応できるのもメリットです。

作業効率化

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

これらよく使うクラスのよく使う処理は、拡張メソッドとして用意しておくと開発効率が上がります。

 using UnityEngine;  

 namespace Hoge.Extensions  
 {
     public static class GameObjectExtensions  
     {
         ///  
         /// 存在しなかった場合はAddComponentする  
         ///  
         public static T GetOrAddComponent(this GameObject target) where T : Component  
         {
             var comp = target.GetComponent();  
             if (comp == null)  
             {
                 comp = target.AddComponent();  
             }

             return comp;  
         }
     }
 }

※GameObjectの拡張メソッド例

拡張メソッドの注意点

拡張メソッドを使用しているのかどうかがパッと見、分かりづらくなるためネームスペースにExtensionsをつけておく事をオススメします。
先の例でいうとnamespace Hoge.Extensionsの部分です。

30.よく使いそうなシェーダーを用意しておく

乗算、加算(カラー加算、加算ブレンドの両方)、ブラーシェーダー等を用意しておくと良いと思います。
※ググれば出てくるので詳細は割愛します

31.テクスチャインポータの作成

ゲームを作っていると様々な画像アセットが必要になります。
ターゲットプラットフォームごとに指定する圧縮テクスチャの種類やクオリティが変わってきます。

これらを毎度設定するのはオペミスに繋がりますし、ミスをしてても気づきづらいため、AssetPostprocessorを使って所定のディレクトリに格納したら、自動でインポータが実行されるようにしておくと良いです。

32.アセットバンドル名を自動で設定されるようにする

アセットバンドルを利用する場合は、参照用のアセットバンドル名を必ず付ける必要があります。
以下は2.Unityプロジェクトディレクトリ構成を決めるで解説したUnityプロジェクトのディレクトリ構成です。

┌ AssetBundleModule/ ・・・サブモジュール  
    ├ AssetBundles/・・・AssetBundleにビルドされるものを格納  
        Resources/  
            ├ chara  
                ├  hoge  
                ├ foo  

AssetBundlesディレクトリ配下に格納すると、AssetPostprocessorで自動でアセットバンドル名が付与されるようにしています。例えばhogeディレクトリにtest.prefabを格納すると、 chara/hoge/testというアセットバンドル名に自動で追加されます。
16.外部アセットを想定したロード処理で説明していますがアセットバンドル名Resources.Loadのパスを共通化するためにResourcesフォルダ名を抜いたパス名にしています

33.最低限使用するであろうアセット導入

以下のアセットはどのようなプロダクトの開発でも必要な汎用性の高いアセットなので、初期から導入しています(執筆時点)。

TexturePackerの採用理由

Unity純正のSpriteAtlasではなく、TexturePackerを採用している理由ですが、以下に挙げている通り、単純にTexturePackerの方がとても優秀だからという点で採用しています。

34.ランタイム中のデバッグ機能としてSRDebuggerの導入

33.最低限使用するであろうアセット導入でも紹介しましたが、SRDebuggerは入れておいた方が良いです。

SRDebuggerとはUnityエディタ、実機上ともにランタイム中のデバッグをしやすくしてくれる外部アセットです。
AssetStoreから購入可能です。リンクはコチラ

詳細は割愛しますが、これひとつでデバッグツールをまかなえるくらい汎用的な神ツールです。

ワークフロー系

35.ローカルで実機ビルドできる環境の整備

自分のPCで実機ビルドできる環境を作っておくのは、プロダクトのプロファイルをする上で大事です。
Xcodeを利用したプロファイルは強力なのでiOSの実機ビルドはできるようにしておくと良いです。

36.アプリ、アセットバンドルのビルド環境整備

アプリ、アセットバンドルのビルド環境は必ず必要になります。
ジェンキンスを使ったビルドジョブを作り、終了したらSlackに通知するようにしています。

アプリはビルドされたら、AppCenter(旧:HockeyApp)などのサービスから開発メンバーに配信できるようにすると良いです。

ビルドされたアプリはビルド番号をアプリ名に入れておくと便利です。

開発初期に暇を持て余しているUnityエンジニアができる42のTips後編_2

イメージこのような感じです。

37.サウンドアセット作成環境構築

Unity標準サウンド以外を使用する事が最初から決まっている場合は、サウンドアセット作成のワークフロー構築に早めに取り組みたいです。
今回はCRIサウンドを使用すると仮定します。
※Unity標準サウンドを使用する場合は不要

CRIサウンドを利用する場合は、オーディオファイルをCRI専用ファイルに変換しなければなりません。

変換処理にAtomCraftを利用する場合、そのワークフローを事前に検証、環境構築しておくと良いです。
また、大人数でAtomCraftを使用する場合、どのファイルをgitignoreに入れなければならないかなど、時間に比較的余裕のある開発序盤に潰しておくと時間を効率に使えます。

38.動画アセット作成環境構築

37.サウンドアセット作成環境構築の動画版となりますが、動画はエンコードの仕方で大きくクオリティが変わってくるので、検証できる環境を用意しておくと良いと思います。

39.環境切り替えツールの導入

ゲームを開発する上で最低限以下の2種類は切り替えます。

その他にもステージング環境、サンドボックス課金環境などプロジェクトによっては様々な環境が必要になります。

環境を切り替えた時には以下の情報を切り替えています。

 public string ApiBaseUrl =>  
  #if DEV  
  "https://dev.sample.com/api/";  
  #elif RELEASE  
  "https://sample.com/api/";  
  #elif LOCAL  
  "https://localhost:8080/api/";  
  #else  
  "https://dev.sample.com/api/";  
  #endif  

※環境毎のAPI接続先切り替えの例です。

これらの情報を切り替えられるようなツールを作っておくと後々楽です。

40.クラッシュレポートの導入

クラッシュレポートは開発序盤から入れるようにしています。
開発序盤はバグも多いためクラッシュの理由をいち早く特定するための材料としてクラッシュレポートは助かります。

オオバが今関わっているプロジェクトではSmartBeatを導入し、レポートの概要はSlackに通知するようにして常にウォッチしている状態です。

41.UIパーツのレギュレーションまとめページを作っておく

UIパーツの命名ルールはエンジニアリングを知っている人が決めるべきだとオオバは思っています。いわゆるTA的な人です。
オオバはTA的な動き方をする事もあるので、皆が見れる場所にUIパーツのレギュレーションページを作っておきます。
今のプロジェクトの場合はConfluenceを利用しています。

最初にひな形を作っておくとメンバーは迷わないので、事前にワークフローを構築しておく事は大事です。

以上の情報を1ページにまとめ、変更が入る度に更新しています。
特に開発序盤は更新頻度が多いので、ある程度落ち着いてからでも問題は無いと思います。

繰り返しになりますが、大事なのはワークフローを事前に作っておく事です。

その他

42.SerializeFieldをつけた時に発生するWarningの除去

最後はとても細かい内容ですが、SerializeFieldアトリビュートをつけるだけで、以下のようなWarningが出てきます。

is never assigned to, and will always have its default value null

Unityを使う身としてはSerializeFieldアトリビュートは必ず使うのでこのWarningは不要です。
初期値を入れれば解決しますがオオバは一括で消し去りたいので、以下Assetsフォルダ直下にcsc.rspファイルを作成します。

 -nowarn:0649  

すると、該当のWarningは消えます。

最後に

前編、後編と長々と書いてきましたがいかがだったでしょうか。
汎用性の高いものだけを紹介しましたが、関わるプロダクトの種類によってはまだまだやる事はあると思います。

仕様がなくてもUnityエンジニアは忙しいということですね(笑)。

今回紹介した大小含めた42のTipsが皆様の開発のお役に立てれば幸いです。

明日は@chrno001さんのソーシャルゲームにおけるマスタ設計~ガチャ編~ - Qiitaです。

開発初期に暇を持て余しているUnityエンジニアができる42のTips前編
前編はコチラです。

オススメ記事