Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
104
Help us understand the problem. What is going on with this article?
@ohbashunsuke

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

本記事はサムザップ #1 AdventCalendar 2020 の12/1の記事です。

※後編記事はコチラ

株式会社サムザップでUnityエンジニアをしている大庭@ohbashunsukeです。

前年に引き続き今年もサムザップ社員エンジニア全員参加のアドベントカレンダーが始まりました。僕は昨年のアドベントカレンダーでも以下のUnity関連のTips記事を執筆しましたが、今年も引き続きUnityにまつわるTipsを執筆していこうと思います。

本Tipsの前提

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

おまえ誰だよ?

最初に軽く自己紹介しておきます。大庭俊介@ohbashunsukeです。
グラフィックデザイナー、Flashデベロッパーを経て、Unityでスマホゲームを作っています。Unity歴は7年くらいで、今までコマンドバトル、ピンボール、麻雀などインゲーム・アウトゲーム・基盤問わず開発に携わってきました。現在は新規開発に携わりつつサムザップエンジニア全体の組織運営に関わっています。
僕の開発思想としてスピードを何よりも重要視しています。ただスピードと言っても雑に作るという意味ではありません。

ゲーム開発に限りませんが実機で触って初めて理解できることが多く、頭の中では上手く行っていることも触ってみるとイマイチな事ってたくさんあります。

「作って評価して壊す」このサイクルをいかにくり返す事が出来るかが、ゲームのクオリティに大きく関わってくると考えています。

そして「作って評価して壊す」をくり返すためには開発スピードが必要になります。
開発序盤は雑でも良いので必要とされる要件を満たして実機で触れる状態、要は適切に評価出来る状態にいち早く到達させます。
評価した結果大半を壊すことになったとしても、早く作っている事で残り時間には余裕があり、作り直すことで更にブラッシュアップされたプロダクトになる可能性が高いです。以上の理由からスピードを意識したモノづくりは利点しか無いと考えています。

そして、今回紹介するTipsは上記の思想を大きく反映しているものとなっています。

弊社エンジニアブログで開発スピードについて「新規プロジェクトでスピード開発を実現するエンジニアの挑戦」というタイトルで寄稿した記事がありますので、気になる方はそちらを読んでみてください。

※ここからが本題です。

■UI設計思想編

新規のゲームUI開発に限りませんが、開発で最も重要なのは「設計」だと考えています。設計次第で中盤から終盤にかける開発スピード、発生するバグの数が雲泥の差で変わってきます。

また中〜大規模のゲーム開発の場合、多くの人が関わるという点もポイントです。
設計次第で投入した人数の割に成果が出ないという事はよくあります。本セクションでは具体的な技術というより設計者のマインド寄りの話に触れていきます。

Tips.1 UI設計者はアプリ全体の設計をする必要がある

初っ端から偉そうな事を書いてしまっている自覚はありつつも自分に言い聞かせるという意味でも敢えて書いています。すみません。

UI設計をするエンジニアはアプリ全体の設計をする意識が必要になります。UIと聞いてパッと思いつくボタンやダイアログ、リストなどの設計をするだけでは足りません。

UIはゲーム起動直後から画面に映し出されます。そして、シーン遷移、画面遷移、通信中、アセットのロードなど、ゲームが起動している最中UIが消えることはありませんし、適切なUXを常に提供し続けなければなりません。

その「適切なUX」は「点」の設計では実現が難しく、全体を包括した「線」、「面」でなくてはいけません。

何が言いたいかというとUXは仕様書やデザインデータからは伝える事が困難です。UI設計を担当するという事は、ゲーム全体の挙動におけるUXの責任が乗っかってくるという事です。

Tips.2 多人数開発が可能であること

本Tipsのターゲットは中〜大規模スマホゲーム開発という事なので多人数が同時開発できる必要性があります。というのも、プロジェクトが進行していくうちに仕様変更によるスケジュールの遅延、大量に発生するバグを収束させる為に人を投入するという事はよくあります。これらを見越して多くのメンバーが同時に開発できる設計は必須です。

これは初期の設計段階から意識しておかねばなりません。途中からでも可能ですが、大きく手戻りする可能性があるのでオススメしません。具体的にどうするか見ていきましょう。

例えば以下のような単位での作業分担です。

  • 各画面単位
  • UIパーツ単位
  • シーン単位
  • ダイアログ単位

画面であれば1人1画面を担当し、複数人がそれぞれの画面を同時編集できる開発が望ましいと考えます。ただし主要画面(例えばホーム、クエストなど)は頻繁な修正・改修が入り、同時に編集する必要が出てくる場合があり、その対策も心がけたい所です。

UnityではPrefab単位にパーツを切り分けておく事ができるため1画面1Prefabの中にNestedPrefab機能を使い、パーツを小分けにして作業分担できるような設計をしておくと更に開発の効率は上がります。
※補足 : 僕自身があまりAdditiveSceneで開発をしないため1画面1シーンについては割愛しています。

具体的な手法は一旦置いておいて、まずはUI設計思想として将来同時多発で開発を行うという事を視野に入れ、他人との作業がコンフリクトし辛い環境にするという視点を持つ事が大事だと思っています。

Tips.3 一度決めた設計で無理して突っ走らない

UIの基本実装が落ち着いてきたとしても、定期的な設計の見直しをする事は大事です。
開発の序盤から全てを考慮することは難しく、ゲームの仕様もどうしても変化していくため、決めた設計のコンセプトから少しずつずれていく事があります。

ずれを感じた際に、思い切って見直す、具体的には壊して作り直すくらいの思い切りも大事な場合があります。

というのも壊す事ができるのはゲームがリリースする前のタイミングでしかできません。リリース後は壊す暇はなく、売上数字とともに突っ走っていくだけなので...。

設計次第で中盤から終盤にかける開発スピード、発生するバグの数が雲泥の差で変わってきます

前述の引用ですが、設計がゲーム開発にとって最も重要なファクターなのでリリース前であれば出来る限り良い状態に持っていくべきで、可能な限り設計にはこだわり抜くのが良いと考えています。

■具体的なUI設計編

今まで設計の思想について触れてきましたが、ここからは具体的なUIの設計について紹介していきます。

Tips.4 エントリーポイントの設計

エントリーポイントとはプログラムの始まりの場所です。
本Tipsのエントリーポイントとは、Unityが隠蔽している厳密なプログラムのエントリーポイントの話ではなく、Unityエンジニアが実際に書いたC#の始まりの部分を指しています。エントリーポイントを設計する上で気をつけている事があります。

  1. どのシーンからでも起動できるようにする
  2. エントリーポイントという事を分かりやすくする

1.どのシーンからでも起動できるようにする

後述の「Tips.5 シーン遷移システムの設計」に繋がりますがアウトゲームシーン担当、インゲームシーン担当と大抵シーン毎に担当が分かれるため、各シーンから直接起動出来る設計をしておくと開発時のストレスが格段に減ります。

それを実現するためにゲーム起動時の一連の処理をまとめておくと良いでしょう。

  • マスターゲット
  • ユーザー作成
  • ログイン
  • チュートリアルスキップ
  • アセットダウンロード

以下のようなエントリーポイントを処理するSceneEntryクラスを定義して各シーンのルートにAddComponentしておきます。

public class SceneEntry : MonoBehaciour
{
    void Awake()
    {
        // Entry Point
        Initialize();
    }

    private async Task Initialize()
    {
        // ゲーム全体で最初の1度しか実行しない処理
        await InitializeIfBootScene();

        if (CurrentScene == "TitleScene")
        {
            // タイトルシーンの場合はユーザーの画面タップを待機する
            await WaitTap();
            // GUIと共に初期化処理を実行する

//~~~~~ 略 ~~~~~

        }
        else
        {
            // 画面タップを待機することなく初期化処理を一気に走らせる
            await MasterGet();
            await CreateUser();
            await Login();
            await SkipTutorial();
            await DownloadAssets();
        }
    }
}

※紹介しているソースコードはあくまでイメージです

このように通常起動フロー、そうではない開発用起動フローを分けて各シーンから起動できるようにしておきます。もちろん開発が進む中で保守するコストは生まれますが、実行時のテストのために毎度ゲームタイトル画面から起動しないといけないという不便さからは解放されます。

UnityEditor実行のような開発中何度も繰り返される事はできる限り時間短縮を意識した設計をしておくと、より多くの開発時間が確保出来るでしょう。

2. エントリーポイントという事を分かりやすくする

新しく参画したメンバーがいち早く戦力になるためには、ソースコードの理解が必須です。UI設計者が出来ることの1つとして学習コストを下げる事を挙げてみます。

プロジェクトのソースコードを理解する上で最初に読むべきポイントは、処理がどこから始まっているかを理解する事。そうエントリーポイントがどこなのかを理解する事です。

Unityは基本的にはヒエラルキーにあるコンポーネントのAwakeやStartメソッドがシーンロード直後に実行されるため、その辺りに目星を付けますがプロジェクトによってはAwakeやStartが複数存在するという事もあります。

そんな時に、ヒエラルキーを見て一発で分かるようにしておくことも、地味ですが開発スピードを上げるためには大切な事だと思っています。


上図のようにパット見でエントリーポイントが分かるようなヒエラルキーになるようにAwake、Startの使用を制限するという事も設計する上で気にしておくと良いかもしれません。この辺りの話題は、後述の「Tips.8 MonoBehaviourクラスのAwake、Startメソッドは極力使わない」で解説しているのでそちらをどうぞ。

Tips.5 シーン遷移システムの設計

  • タイトルシーン
  • アウトゲームシーン
  • バトルシーン
  • バトルリザルトシーン
  • ストーリーシーン

といった多人数開発・リソース管理を考慮してシーン分けをする事が多いと思います。

シーン遷移はUnityが提供するSceneManagerクラスを使うことになりますが、そのままベタ書きせずにラッパークラスを用意します。理由としてはシーン遷移中には下記のようなUIの表示・機能が必要になるためです。

  • Tipsの表示
  • ローディングの表示
  • シーン間のデータ送信
  • アセットのダウンロードまたはロード
  • 現在のシーン、遷移するシーンの取得
// シーン遷移前処理
ShowTips();
ShowLoading();
// シーン遷移開始
SceneManaer.LoadScene("InGameScene");

//~~~~ 略 ~~~~

// シーン遷移後にシーン遷移中UIを非表示
HideTips();
HideLoading();

上記のような各遷移処理毎に同じようなコードを書きたくないため、
ラッパークラスの中に隠蔽するなどして処理をまとめた方が良いでしょう。

ここではSceneManagerをラップしたSceneManagerWrapperクラスを用意したとします。

  • シーン遷移開始処理
  • シーン遷移完了後の処理

👆 これらのタイミングで実行するデリゲートをセットできるようにします。

SceneManager.cs
public class SceneManagerWrapper
{
    // シーン遷移開始時に呼ばれる
    public static Action onStartLoad;

    // シーン遷移が完了したら呼ばれる
    public static Action onCompleteLoad;

    // シーンのロード開始
    public static async Task LoadSceneAsync(
        string sceneName, object data){ /*割愛*/ }

    // シーン間で渡すデータを取得する
    public static T GetData<T>(){ /*割愛*/ }
//~~~~~ 略 ~~~~~

}

👆 ※SceneManagerラッパークラスのソースコードのイメージです

ゲーム開始時のタイミングでイベント登録

以下のような感じでシーンの遷移開始・完了時のイベントにゲーム通して使われる処理を登録しておきます。
ここではTip/ローディングの表示非表示処理です。

// シーン遷移開始処理
SceneManagerWrapper.onStartLoad += ()=> {
    ShowTips();
    ShowLoading();
};

// シーン遷移完了後の処理
SceneManagerWrapper.onCompleteLoad += ()=> {
    HideTips();
    HideLoading();
};

シーン遷移時の処理

// シーン遷移開始
await SceneManagerWrapper
    .LoadSceneAsync("InGameScene", new ToInGameSceneData{ battleId = _battleId });

シーンをロードする際はこのような感じで実行するイメージです。
この例ではバトルに遷移する想定なのでバトルIDを引き渡しています。

シーン間のデータ受け取り

// 遷移先シーンでシーン遷移間のデータを受け取る
var data = SceneManagerWrapper.GetData<ToInGameSceneData>();

シーン間でデータをやり取りすることはよくあるので、
SceneManagerWrapperに実装しておきます。

ここではGetDataというメソッドを定義しておき、
シーン遷移時に保持しておいたデータを受け取る
という想定で実装しています。

前述の「Tips.4 エントリーポイントの設計」
現在のシーンを取得するAPIをこのラッパークラスで提供しています。

ここまではエンジニアリングな話でしたが後述の「Tips.7 画面遷移システムの設計」も同様ですが、遷移中のUIをどうするのかを予めUIデザイナーと連携をとっておく必要があります。

  • ローディングを表示する
  • 通信中を表示する
  • Tipsを表示する
  • Tipsを表示するならどこからそのデータを取得するか?
  • 表示のアニメーションのタイミング

などなど。


TitleSceneからOutGameSceneにシンプルに遷移してしまうと、TitleSceneを破棄したタイミングで一瞬何も無い状態が画面に表示されてしまいます。

この辺りは後述の「Tips.6 シーン間を跨ぐものはDontDestroyOnloadへ」で説明していますが、以下のようにシーンの継ぎ目が見えないようにして、ローディングやTipsを表示させる設計をします。

この辺りはメモリ解放など技術的な話も多く、エンジニア主導で話を進めていかないと、プロジェクトが前に進まない可能性があるため、エンジニア側から解決手段を提供すると良いかもしれません。

システム面、UI/UX面全てを包括した形でシーン遷移のシステムは作っていく必要があるという事になります。

Tips.6 シーン間を跨ぐものはDontDestroyOnloadへ

  • ダイアログ
  • ローディング
  • タップ・スワイプエフェクト

上記のようなシーンをまたいで使用する共通オブジェクトはシーン遷移で破棄したくないので、DontDestroyOnload領域に生成するようにしています。

前述の「Tips4. エントリーポイントの設計」と関連して、ゲーム全体で最初の一度しか実行しない処理の中で実行するような設計になっています。これにより各シーンから実行する際も共通オブジェクトは何も特殊な処理を挟む事なく使用できるようになっています。

注意点としてシーン遷移間で破棄されないため、メモリーリークする可能性があるため注意です。

Tips.7 画面遷移システムの設計

前述の「Tips.5 シーン遷移システムの設計」と似ていますが、こちらは1つのシーン内で発生する画面遷移の話になります。前提の通り複数人で開発出来るよう、1画面1Prefabの単位で分けて設計しています。

画面遷移処理の流れ

  1. ボタンなどのトリガーから画面遷移リクエストをマネージャに送る
  2. マネージャから画面遷移管理へ次の画面遷移をリクエスト
  3. 画面Poolerから次の画面を取得(新規生成 or キャッシュを返却)
  4. 古い画面と次の画面を入れ替える

図にすると以下のようなイメージです。

画面遷移システムを設計する上で以下のような事を考えておく必要が出てきます。

  1. どの画面からも遷移でき、どの画面へも遷移できる
  2. Androidバックキー対応
  3. 画面遷移中のユーザー入力への対応

1. どの画面からも遷移でき、どの画面へも遷移できる

プロジェクト初期は「画面Bは画面Aからしか遷移することはありません」という仕様だったとしても、開発中盤で「やっぱり画面Cからも遷移することになりました!!」みたいな仕様変更はよく発生することです。
これは本当によくあることなので、予め画面はどの画面からでも遷移できるように作って汎用性を高めておくのが良いです。

2. Androidバックキー対応

Androidバックキー対応も画面遷移システムを設計する上で重要なポイントになります。戻るの要件はプロジェクトごとに変わってきますが、基本的には遷移前の画面に遷移するという事になります。実装方法は様々ありますが、例として履歴を保持するやり方を挙げてみます。
戻るが実行されたら画面遷移履歴リストから一つ前の画面情報を取得して遷移させるというやり方です。そのために、画面遷移履歴情報と現在の画面情報を画面遷移マネージャに保持しておきます。

3. 画面遷移中のユーザー入力への対応

画面遷移中のユーザー入力に対してどこまで対応するのかは悩みどころです。画面Aに遷移中に画面Bに遷移するユーザー入力を受け取った場合、画面Aに遷移する処理を全てキャンセルする必要があります。

  • アセットのロードキャンセル
  • ロード済みアセットの破棄
  • 各処理の中断

などなど。各画面実装の複雑さが増していき、学習コストが上がります。またこれをテストするコストも高くなります。
以上の事を踏まえると画面遷移中の割り込み処理対応はコスト高めです。
手っ取り早いやり方としては、遷移中はユーザー入力を受け付けないという割り切りも視野に入れて工数を見積もった方がよいと考えています。
画面遷移マネージャが遷移状態を管理するようにして、遷移中はユーザー入力をブロックする処理を実行するような仕組みで実装します。

// クエストトップへ画面遷移リクエスト
await DisplayManager.Goto(DisplayType.QuestTop, new ToQuestTopData{
    // 表示させるクエストのIDを指定
    questId = _questId
});

※画面遷移サンプルコード

その他

また画面全体、一部で使うヘッダやフッターのような共通UIパーツの扱いも設計する上では考えておく必要があります。出来る限り各画面のユニークな実装処理を減らすように基盤システムを構築できるかが、その後の開発効率につながると考えています。

Tips.8 ダイアログシステムの設計

「Tips.7 画面遷移システムの設計」と同様、同時に複数人で開発出来るよう、1ダイアログ1Prefabの単位で分けて設計しています。

// アラートダイアログを開く
var alertDialog = await DialogManager.Open(
    new AlertDialogData{ title = _title, message = _message }
);

※ダイアログを開くサンプルコード

大抵必要になる要件として以下。

  1. Androidバックキー対応への配慮
  2. 結局ダイアログの上にダイアログはいくつも重なる事になる

1. Androidバックキー対応への配慮

Androidバックキー対応は、単純に重なっているダイアログを順番に閉じていく。または閉じてはいけないものもあるので、閉じては行けないダイアログが最前面の場合はAndroidバックキーが効かなくなるといった制御が必要になります。

2. 結局ダイアログの上にダイアログはいくつも重なる事になる

デザイナー的にダイアログの上にダイアログを載せたくない要望が出てくる事がありますが、プロジェクトが進んでいくうちに、ショップ購入確認ダイアログや例外処理のエラーダイアログをどうしても重ねざるを得ない状態になったりします。

ということで、僕は理想は追いかけつつも最初からダイアログは重なっていくことを前提に設計を予めしておきます。

Tips.9 MonoBehaviourクラスのAwake、Startメソッドは極力使わない

若干UI設計とは離れますが、大事な事なので差し込んでいます。
UnityエンジニアにとってのエントリーポイントとなるAwake、Startメソッドはとても便利な半面、多用しすぎると見通しが悪くなる、また処理順を保証できなくなってきます。

// A.cs
void Awake()
{
    // Do Something.
}

// B.cs
void Awake()
{
    // Do Something.
}

A、Bとコンポーネントヒエラルキーに存在している場合、この2つのAwakeの処理順はどちらが先に実行されるかは保証されません。1
処理順を把握できないという事は、処理順によるバグを生むリスクも伴います。

例) A => B という順にAwakeが呼ばれている場合は成功していた処理が、B => Aと呼ばれる事によって不具合が起きるといったものです。

改善の一例

下記のようにAwakeの回数を最小限に留めてそれに代わる処理(Initialize等)のメソッドを定義し、明示的に実行させる方が良いと考えています。

// A.cs (EntryPoint)
void Awake()
{
    _b.Initialize();
}

// B.cs
public void Initialize()
{
    // Do something.
}

個人で開発する時は、逆にAwakeやStartを使わない事が面倒くさいと感じることが多いかもしれませんが、中〜大規模の集団開発となるとAwake、Startの乱用がカオス化を招きます。
Awake、Startなどを使わないルールを設けることで逆に開発の効率が上がるのではないかと思っています。

Tips.10 Androidバックキーの事を忘れないで

今まで何度か出てきましたが、UIを設計する上でAndroidバックキーの存在を忘れてはいけません。

常に「Androidバックキーが今押されたらどうなるだろう?」という事を頭の片隅に置きつつ設計しておかないと、後から大きく見直す必要が出てきます。

以下のような優先順位で実装しておくと良いかなと思っています。

  1. ユーザー入力をブロックしていたら処理しない
  2. ダイアログのAndroidバックキー処理
  3. 画面のAndroidバックキー処理
// Androidバックキーが押された時の処理
void OnExecuteAndroidBackKey()
{
    // 画面遷移中などのユーザー入力をブロックしている時はAndroidバックキーは処理しない
    if (UIBlocking.IsEnabled()) return;

    // 画面全面のダイアログを優先して処理(処理を実行したらtrueを返却)
    if (DialogManager.OnExecuteAndroidBackKey()) return;

    // 画面側の戻る処理(処理を実行したらtrueを返却)
    if (DisplayManager.OnExecuteAndroidBackKey()) return;
}

Androidバックキー処理のサンプルコードですが、各マネージャクラスにAndroidバックキー処理をリクエストします。

常日頃からAndroidバックキーを実行する

画面遷移などの基盤に寄せた処理の場合はAndroidバックキー対応の抜け漏れは発生しづらいですが、各画面のユニークな演出中のAndroidバックキー対応は漏れがちです。
(例 : 強化演出中、ガチャ演出中など)

UnityEditorで開発中はエスケープキーを日常的に押して挙動的に大丈夫か習慣づけておくと良いでしょう。

Tips.11 戻るの設計

Androidバックキー対応と重複する部分がありますがUI上に表示する戻るボタンの対応についてです。
もちろんゲームの仕様によって戻るの要件は様々なので、一概に何が正しいはありませんが出来るだけシンプルに実装しておくのが良いと思っています。

例えば以下のような実装が考えられます。

  • 各画面の履歴を保持しておく
  • 戻るボタンが押されたら履歴から取り出して遷移
  • 履歴がなくなったら最初の画面に強制的に遷移
  • 画面毎の戻るの挙動を変更する場合は処理をオーバーライド

※画面遷移については前述の「Tips.7 画面遷移システムの設計」で説明しているので割愛します。

Unityで戻るを実装する時に複雑化しやすいのはシーンを跨いだ時の戻るの挙動です。
シーンを跨ぐと前のシーンの情報は基本的にメモリから破棄されます。履歴情報が破棄された状態から戻るということは、何かしらの情報を元に戻り先を作らなければなりません。

シンプルに最初の画面に戻すといった要件であれば簡単ですが、UX的にどうしてもそれでは不便という事で対応する必要も出て来る場合もあります。

このようなユニークな処理を実現するために、「画面毎の戻るの挙動を変更する場合は処理をオーバーライド」が出来るような設計にして、ある程度の仕様変更に耐えうる状態にしておくのが良いと考えています。

Tips.12 GameObjectはキャッシュして体感アップ

画面・ダイアログを表示する度にそれらを生成(Instantiate)していては体感が損なう場合があります。プロファイラーで計測すると分かりますがInstantiate処理はCPU負荷が高く低スペック端末だと顕著にフレームレートに響いてきます。

最低でもよく使う画面やダイアログはシーンロード時についでに生成してシーン内にキャッシュしておく設計にしてゲームプレイ中の生成コストを下げ、ゲームの触り心地を良くします。

キャッシュする事で、状態の管理が複雑化してしまいがちですが、そこは基板側の設計で吸収してあげるのが良いと考えています。表示の初期化や後始末忘れを回避するために開発者に提供するメソッドは絞ると良いでしょう。

public abstract class DialogBase : MonoBehaviour
{
        // ダイアログを開く前に呼ばれる初期化メソッド
        // キャッシュを再利用した際のリセット処理も兼ねる
        public virtual async Task ReInitialize(){}

        // ダイアログを開くメソッド
        public virtual async Task Open()
        {
                // 共通のダイアログ表示アニメーション
                // 特殊ケースの場合は上書きする
        }

        // ダイアログを閉じるメソッド
        public virtual async Task Close()
        {
                // 共通のダイアログを閉じるアニメーション
                // 特殊ケースの場合は上書きする
        }

        // ダイアログが閉じてアセットの破棄などを実行するメソッド
        public virtual void CloseComplete(){}
}

ソースコードはイメージですが、上記のような感じでベースクラスで各種イベントで実行されるメソッドが定義されていて、それをサブクラス側で具体的な処理を書いていきます。

Tips.13 UIアニメーションの実装方法基準

UIアニメーションをどうやって実装するかは悩み所です。

僕も毎度とても悩んでいます。ただ、何度か経験する中で一つの基準が出来たので紹介します。

結論から書きます。

  • 再利用するものはスクリプト
  • 再利用しないものは何でもいい

極端に聞こえるかもしれません。詳しくは今年11月のUnity勉強会「yokohama.unity#4」で発表した資料がありますので、ご参考にどうぞ。



LT版クリエーターとUnityエンジニアの狭間でUIアニメーションを設計する3つのTips/yokohama-unity4 - Speaker Deck

※UIアニメーションを具体的にどう作るかといったワークフローについては後編で執筆予定です

■後回しにしない方が良い事編

当たり前だと思いますが影響範囲が大きいものは早めに設計の目処をつけておきたいです。

この章では、明らかに最初に手を付けておかないといけないものから、パッと見後から実装しても大丈夫そうに見えるけど序盤にケリをつけておいた方が良さそうなUI周りの設計について紹介していきます。

Tips.14 UI解像度を決めてから本格的に動き出す

UIの解像度は開発序盤に決めておく必要があります。これが決まらないとデザイナーの元素材の解像度が決まらず、デザイナー・Unityエンジニア共に作業が出来ません。
※作業出来なくもないですが、高確率で作り直し確定です。

ちなみに僕は以下のような決め方をしています。

  • 基準となるスマホ端末を決める
  • 検証用の仮UIを用意して解像度毎に実機で確認

基準となるスマホ端末を決める

基準となるスマホ端末の決め方は、そのゲームのメインターゲットや戦略、その時その時の状況によって変わるためプロジェクト内で話あって決めます。

検証用の仮UIを用意して解像度毎に実機で確認

大事なのはスマホ実機で実際に見て確認するです。

ターゲットユーザー層に対してどのくらいのクオリティを提供しないといけないかプロデューサー・プランナー・デザイナーと相談することになります。

繰り返しになりますが大きな手戻りが発生する可能性があるため、UI解像度を決めてから本格的に動き出すことをオススメします。

Tips.15 セーフエリア対応

iPhoneX以降対応する必要のあるセーフエリアですが、これも後回しにすると地獄を見る案件です。

「セーフエリア対応処理を入れたらUIが重なって全画面調整する必要が出てきた」といった事がプロジェクト後半UIが量産された状態で発生すると深刻な手戻りコストになります。

そうならないように、開発序盤からセーフエリアに対する要件を決めて設計しておく方が良いでしょう。

Tips.16 UIの階層関係を決めておく

経験上以下のような階層構造になることが多いです。
※上から順に前面に表示されるもの

  1. タップエフェクト
  2. ローディングなどの最前面表示UI
  3. システム系ダイアログ
  4. 通常ダイアログ
  5. コンテンツUI
  6. 背景

システムダイアログ、通常ダイアログはそれぞれの階層で複数ダイアログが重なるような設計にする事になります。

タップエフェクトもこの階層を決める段階で実装しておく方が良いと考えます。パッと見後から実装しても大丈夫そうではありますが、階層構造を後から手を加えるのはリスクなので、序盤に仕組みを固めておくことを心がけています。

Tips.17 通信・アセットのダウンロード・ロード処理

「Tips.1 UI設計者はアプリ全体の設計をする必要がある」と関連した内容で、本来のUI開発の範疇なのかは微妙なラインですが、通信周りの設計はUXのクオリティを上げるために無視できません。

開発序盤のタイミングで、エンジニア側から通信やロードタイミングのすり合わせをUIデザイナーとしておくと良いでしょう。UIデザイナー側、Unityエンジニア側共に譲れない、譲りづらい部分があると思います。その辺りを開発序盤から話し合っておくと後々のトラブルが少なくなる印象です。

よく発生しがちなケースとして、UIデザイナーが想定していないタイミングで通信処理が走っていて、予想していたタイミングで表示されないといった認識のズレです。

仕様の変更やブラッシュアップで通信のタイミングが増加、変更する事は、開発中によくありますが、UXを損なっていないかという視点も大切です。

通信やアセットのロードのタイミングなどに変更が入る場合はUIデザイナーと認識を合わせておくと良いでしょう。

最後に

いかがでしたでしょうか。スケジュールが潤沢ではないUnityを使った中〜大規模スマホゲーム開発におけるUI開発前編(Tips.1〜17)を紹介してきました。

  • Tips.1 UI設計者はアプリ全体の設計をする必要がある
  • Tips.2 多人数開発が可能であること
  • Tips.3 一度決めた設計で無理して突っ走らない
  • Tips.4 エントリーポイントの設計
  • Tips.5 シーン遷移システムの設計
  • Tips.6 シーン間を跨ぐものはDontDestroyOnloadへ
  • Tips.7 画面遷移システムの設計
  • Tips.8 ダイアログシステムの設計
  • Tips.9 MonoBehaviourクラスのAwake、Startメソッドは極力使わない
  • Tips.10 Androidバックキーの事を忘れないで
  • Tips.11 戻るの設計
  • Tips.12 GameObjectはキャッシュして体感アップ
  • Tips.13 UIアニメーションの実装方法基準
  • Tips.14 UI解像度を決めてから本格的に動き出す
  • Tips.15 セーフエリア対応
  • Tips.16 UIの階層関係を決めておく
  • Tips.17 通信・アセットのダウンロード・ロード処理

何か1つでも役に立つものがあれば幸いです。
続きのTips.18〜39は以下の内容について書いていくつもりで12/22リリース予定。

※後編リリースしました。

  • UIレギュレーション編
  • UIアセットワークフロー構築編
  • UI担当Unityエンジニアマインド編
  • UI開発Tipsおまけ編

2020年Qiitaアドベントカレンダーは始まったばかりです。
楽しんでいきましょう。

明日は@Gaku_Ishiiさんの「C#のネイティブ関数呼び出し(P/Invoke)時に行われていることを調べてみた」です。お楽しみに!!

サムザップのアドベントカレンダーは人数の関係上2つあります。
こちらもよろしくお願いいたします!
サムザップ #2 Advent Calendar 2020 - Qiita


  1. Script Execution Orderで指定は可能 

104
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ohbashunsuke
Twitterで初学者にUnityのチーム開発ノウハウを分かりやすくお届け。元デザイナー経験を生かしクリエーターと連携したエンジニアリング情報を共有しています。 🏢 株式会社サイバーエージェント ゲーム部門所属
engineerlife
技術力をベースに人生を謳歌する人たちのコミュニティです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
104
Help us understand the problem. What is going on with this article?