UI組み込みをデザイナーさんに任せるための設計(メルモンでの事例)
「フィーリアのモンスターといっしょ!」(通称メルモン)の開発に関する内容です。
※ メルモンの基盤の制作はぼくしか関わっておらず、個人の見解となります。
メルモンではスキル向上や工数のことを考え、
UIデザイナーさんにUIやアニメーションの組み込みまでしていただきました。
ぼく自身、UIデザイナーさんに組み込みをしていただくような環境で作業をしたことはなかったため、どうなるのか好奇心半分、不安半分というところでした。
とてもざっくりですが、図のような分担です。
ここでは、主に「View用のプログラム」について、
UIデザイナーさんと並行開発できるよう、どのように設計していったかを書いてみようと思います。
参考になることがあれば幸いです。
前提
この分担で作業するにあたり最も気を使った点は、以下の2点となります。
- UIデザイナーさんは、プログラム(Component)のことをほぼ意識しない
- UIデザイナーさんとエンジニアは並行開発
Componentについて、
ラッパークラスとなるComponentは必要なので、「テキスト用のComponent」や「アニメーション用のComponent」など、大きなくくりのComponentを用意しました。
ただし、モンスターの名前テキスト表示Component、さんぽのテキスト表示Componentというように、表示内容ごとのComponentは作ってはいません。
考えることが増えることで、どうしてもミスが発生するためです。
残念なことに、少人数かつ運用タイトルではないメルモンでは、
都度フォローする余裕も、
後から直す余裕も、
使いやすいようリファクタリングしていく余裕もありません。
そんな中でも、大きなくくりで汎用的に作ることでコピペに耐えれるようになり、ミスやコンフリクトが発生しにくくなりました。
View用のプログラム
「View用のプログラム」には以下のようなものがあります。
細かい話ですが、それぞれ見ていきます。
1. 画面ステータス
まず、一般的に、「ボタンを押す」→「表示の状態が変わる」という流れを想定します。
メルモンのUIは、以下の動画のように同じ画面内でメニューが切り替わることが多いです。
この状態ごとに、「育成画面」「ごはん選択画面」「メニュー画面」などという画面の名前(ステータス)をつけており、
1. ボタンを押して、画面のステータスを変える
2. 画面のステータスに合わせて、各ボタンのアニメーションが動き、表示が変わる
という挙動になっています。
エンジニアは、画面のステータスを変更する処理を作成し、
UIデザイナーさんには、画面のステータスに合わせて表示が切り替わるアニメーションを作成 していただいています。
(ボタンを使わず画面のステータスを切り替える機能はエディタ拡張で作成しました)
独立した開発ができ、処理も単純なので、結合した時も不具合は起きづらくなっています。
2. イベント制御
UniRxを使ったイベントやデリゲートを多用しています。
例えばボタンの制御は、
テクスチャのComponentにイベントを生やしておき、Presenterから購読しています。
Presenterは、そのイベントが発火すれば、画面のステータスを切り替えるという使い方ですね。
このように設計することで、
Eventを購読していれば実行されるし、無ければ何も起きません。
購読の有無は画面毎に作られたPresenterに依存するため、View側は汎用的になります。
この考えは他のものにも当てはまります。
メルモンで最も複雑なComponentはSpineComponentですが、
そこにも業務プログラムはほとんど入っておらず、タイミングごとにEventがあるだけです。
例えば、モンスターが特定のモーションをすると、フィーリアの挙動が変わることがあります。
- モンスターは、特定のモーションを実行しただけ
- Presenterは、購読と、イベント発火時にフィーリアにモーションの指定をしただけ
- フィーリアは、言われた通りにモーションを実行するだけ
ですね。
Presenterは、どのモンスターに対しても、特定のモーションに対して購読していますが、
そのモンスターが、対象のモーションを行わない限り、実行されることはありません。
3. SerializeField
表示部分は、内部的には以下のような設計にしています。
VContainerを使用し、画面の項目毎にLifetimeScopeを用意しています。
LifetimeScopeごとに要素ごとのComponentをアタッチするためのRequireViews
というクラスのSerializeFieldを持っています。
アタッチされたComponentと、生成時に渡されたParameterとをかけ合わせ、表示をおこないます。
この設計によりUIデザイナーさんとエンジニアの作業が交わるのは、RequireViewsへのアタッチのみとなり、お互いの作業状況によらず並行開発が可能になります。
UIデザイナーさんは画面のステータスがあれば画面を作れますし、
エンジニアは画面が無くてもRequireViewsというインターフェイスがあるので、そこから処理を作ることが可能です。
4. フォーマット
ここでは、表示する文字列などのフォーマット(整形)という意味です。
フォーマットなどは、View側に持ちたい気持ちが強いのですが、
今回は、上述の通りPresenterやModel に持っています。
設計上、ViewやModelには状態による分岐をできる限り持たせないようにしています。
文字列だと単純すぎなので、パラメータが多いSpineを例にします。
Spineの表示分岐をView側に持つと以下のようになります。
「フィーリアを表示して!」と頼めば上手いことやってくれる便利なView です。
処理が1箇所にまとまることで管理しやすいですし、
少なくとも最初は綺麗に共通化できます。
(経験則で)これの欠点として、
- 開発後半で分岐が複雑になりがち
- 分岐だけで吸収できず微妙なフラグ管理をしがち
が挙げられます。
その結果、育成画面の修正をしたら、散歩画面で不具合が発生するようなことになります。
メルモンではこのようにしています。
設定通りの何かを表示するView です。
View は何を表示しているかは知りません。
設定の方が冗長になりがちですが、絶対に他への影響を出さないという強い意志を込めました。
実際は、設定の部分をModelにしており、必要に応じて使い分けています。
設定が変われば中に分岐を作るのではなく、設定自体をコピペして増やしていきます。
項目の追加削除は面倒ではありますが、それぞれが簡素なので、分岐の中を注意深く直していくよりは楽だと感じました。
また、他への影響が無いため、リファクタが非常に気軽です。
今回の基盤は何度も大きなリファクタをしていますが、我ながらスムーズに動くことにびっくりしていました。
5. SE(サウンドエフェクト)
こういうのもありなのかという閃きがあった部分なので紹介します。
当初、SEは「ボタンを押した時に鳴る」ということで、ボタンのComponentに依存して鳴らすようにしました。
ですが、「ボタンを押した時にダイアログが開く」というパターンでは、「ボタンのSE」「ダイアログが開くSE」の両方が鳴ってしまいます。
そもそも「ダイアログが開く」というのはボタンでも無いので、ボタンに依存していたComponentは使えません。
SE用のComponentが増えるのもなぁ…ということで、ボタンのComponentに依存するのは却下。
試行錯誤した結果、アニメーションのComponentに依存して鳴らすようにしました。
メルモンでは、ボタンやダイヤログ全てにアニメーションが付いています。
また、アニメーションのComponentも汎用的になっていることから、
アニメーションの実行時にイベントを生やし、それをSEのComponentが購読する形で実装しています。
これにより、アチーブメントの解放演出など、ユーザー操作起因ではないものにも使えるComponentになりました。
以上です。
UIデザイナーさんは本格的にUnityを使うのは初めてだったこともあり、楽しいところだけを触っていただけるよう設計してみました。
結果として、アニメーションもしっかりと入れていただいた上で、Prefabのコンフリクトも起きることもなく意外とスムーズに進めれたかと思います。
運用タイトルの基盤として耐えれるかはわかりませんが、小さいアプリであれば使いやすく感じました。
記事を読んでいただきありがとうございました。
ところで…!
メルモンのリリースから約半年、AR機能なども含め楽しんでいただけているようでありがとうございます。
多くのかたが、しぐさの全開放や規格外への育成まで進めてくれており、非常に嬉しく思います。
実は、全てのさんぽを見ると発生する「おもいで、たくさん」という隠しさんぽがあるのはご存知でしょうか?
進行状況などがわからず非常に申し訳ないと思っているのですが、ぜひ探してみてくださいね。
あとあと、最近とくしゅのしぐさが見つからないという嘆きをみかけます。
大部分はモンスターのサイズが関係していますので、特定のサイズまで育てることを優先してからさんぽに行くといいかも…?です。
(ヒントはここまで)
Discussion