- 00:03 はじめまして、アンディーと申します。
- 00:07 KLab株式会社に勤めていて、そこのエンジニアリングの組織に所属しています。
- 00:15 ゲーム業界じゃない人にどこに勤めているのと聞かれると、
- 00:19 KLabですと答えて、そのあとにどこにあるんですかで、六本木と言うと
- 00:25 みんな勘違いする人が多いんです。
- 00:31 そういう話が今日のテーマではないです。今日のテーマはUnityにおける疎結合設計
- 00:40 割とよくないタイトルだと思うんですけれども、たくさんの人が来てくれてありがとうございます。
- 00:46 このセッションはあまりテクニカルな話ではなく
- 00:51 どちらかというとワークフロー的な概念が多いです。
- 00:57 基本的にワークフローとデータとコードはどうやって連携しているのか
- 01:02 そして、その連携の仕方がよろしくないとどういう結末になるのかというのがテーマになっています。
- 01:09 そしてそれを解決していきたい。
- 01:16 そうですね、まずはアジェンダからいってみましょう。4つの
- 01:20 トピックがあって、 まずはUIのワークフローの面を解説していきたいです。
- 01:28 そのあとは
- 01:30 結語
- 01:31 ということについてちょっと話したいです。そして特にその結合はUIとかのワークフローと
- 01:37 どうつながっているのか解説していきたいです。
- 01:41 そしてそのあとは、UIアゲインというちょっとダサい
- 01:47 項目になっているんですけれども、そこは実際にそのワークフローと
- 01:51 結合をどうやってUnityでマネージできるのかというのをちょっと解説していきたい。そのあとは、
- 01:56 ダイジェストに入ります。
- 02:00 早速UIからちょっとだけいってみましょう。
- 02:06 大前提としては、UnityとUnity EditorでUIをビジュアルに作ることができます。
- 02:15 ビジュアルというのは、コーディングはそんなにいらない。
- 02:18 プログラマじゃなくても、Editorの機能を使って、ドラッグ&ドロップで
- 02:23 レイアウトを作ったり
- 02:25 アニメーションクリップで
- 02:27 UIのアニメーションができたり、あとはロジックも
- 02:30 ドラッグ&ドロップで作れたりします。
- 02:34 海外の人もそう言っているかわからないですけれども、日本人はよくuGUI
- 02:39 いいますよね、たぶん。
- 02:40 なので正式名称じゃない気がしますけれども、uGUIというのはあります。
- 02:46 そしてビジュアルに作れます。そにれも関わらず、
- 02:51 デザイナーではなく
- 02:53 プログラマがUIを作ることは
- 02:57 私の経験で言うと割と多いです。
- 03:02 そしてプログラマがUIを制作すると、大体そういうワークフローになりがちです。
- 03:11 UIのデザイナーはフォトショップなどで
- 03:15 まずはアセットを作ります。ボタンであったり
- 03:19 を作ります。そのあとは
- 03:22 実際にプログラマは組み込みをやりますので、
- 03:26 仕様書を書く。
- 03:29 そしてプログラマはその仕様書を一生懸命読んで、
- 03:34 Unityで仕様書に従って、タブに従って実装する。
- 03:40 その結果をまたUIのデザイナーがレビューして、
- 03:46 OKだったら次のステップに入るんですけれども
- 03:49 大丈夫じゃなかったら、最悪アセットのやり直しまで、
- 03:55 戻ります。
- 03:58 ここに書いてある通り、そのワークフローは
- 04:01 あったりしますけど、The Badと書いてありますので、それはよくないワークフロー。
- 04:07 なぜかというと
- 04:10 スループットが低い
- 04:13 基本的にまずはデザイナーが作業をします。そのあと、エンジニアがその作業を終わるまで待たないといけない。
- 04:21 そして自分の作業に入ります。
- 04:23 そのあと
- 04:24 またデザイナーに戻ります。
- 04:27 そこはチェーンになっていて、
- 04:31 同時に作業ができない。 そしてイテレーションが遅い。なぜかというと
- 04:39 ステップ がワークフローのセットは割と多いです。
- 04:43 そして本来
- 04:45 いらないタスクまで発生する。
- 04:48 一瞬戻りますと、
- 04:50 UIデザイナーは仕様書を書かなきゃいけない。なぜかというと、デザイナーは組み込みをやらないからです。
- 04:57 そしてプログラマも仕様書を読まなきゃいけない。それは本来やらなくてもいいはずのタスク
- 05:05 昨日のシェーダーのトークセッションに出た方がいらっしゃったら
- 05:12 アークシステムワークスの本村さんは面白いことを言っていたんです。基本的にアートは
- 05:17 言葉にしにくい
- 05:20 そのデザイナーはその仕様書を書くときに
- 05:24 場合によって、正しい言葉を見つけられないかもしれない。そして
- 05:29 エンジニアプログラマーはその仕様書を読んで、正しく理解しない可能性も十分ある。
- 05:37 それによってもしかすると望ましくない結果になる
- 05:43 場合があります。
- 05:46 なので、もっといいワークフローはこんな感じです。
- 05:51 UIデザイナーは
- 05:53 アセットを作って
- 05:55 UIを作る
- 05:57 そしてレビューする
- 05:59 割とシンプルなワークフロー。そして同時にプログラマは
- 06:04 デザイナーのサポートをする。
- 06:07 そしてコードを最適化する。
- 06:10 上の方は割とアセットの制作とUIの制作とレビューはたぶん
- 06:16 みんなわかってらっしゃる思うんですけれども、その下の
- 06:19 デザイナーのサポートと、コードの最適化が何を指しているかというと
- 06:25 uGUIは
- 06:26 あるのはある、そして使えるのは使えるですけれども、それをそのままプロダクションで使おうとすると
- 06:34 機能が足りなかったり
- 06:36 パフォーマンスがよくなかったり、またはデザイナーの作業の時に
- 06:42 効率が悪かったりする。
- 06:45 それを
- 06:46 UIとUIデザイナーだけで解決しない問題が多い。
- 06:52 なのでもっといいワークフローの時に
- 06:56 プログラマは
- 06:58 デザイナーのサポートに入って一緒に効率化を上げる。
- 07:04 パフォーマンスを上げる。
- 07:07 その時のプログラマの課題はどっちかというと、コンテンツを作るのではなく、
- 07:14 デザイナーのためのツールを作る
- 07:18 というワークフローになります。そしてそういう意識になる。なのでプログラマはコンテンツを作らない
- 07:25 コンテンツを作れるデザイナーのためのツールを提供する。
- 07:30 そのワークフローの
- 07:34 おいしいところはスループットが高い。イテレーションが早い。もしも
- 07:42 パフォーマンスとか見た目とか実際のユーエックスが
- 07:47 思っていたほどよくなかったらそれが割とすぐ見つかったりします。そしてすぐに対応できます
- 07:54 そしてそれを改善する必要があれば
- 07:58 おそらくプログラマよりデザイナーがその改善を担当したほうが早かったり
- 08:04 効率がよかったりします。そして品質もアップしたりします
- 08:11 このワークフローのほうがGoodなのはGoodですね。
- 08:19 じゃあそのワークフローの違いはなんなのか
- 08:24 というと
- 08:26 いろんな答えがあります。チームにプログラマしかいない。
- 08:30 そもそもそのワークフローは成立しない。
- 08:33 なんですけど
- 08:34 ここではとりあえず、ちゃんとUIデザイナーがそのプロジェクトに入っている前提で話を進めていきましょう。
- 08:42 その場合の
- 08:44 Goodのワークフローへの道は結合にあります。
- 08:51 いい感じの結合にあります。
- 08:54 まずは私がドイツ出身で、どうでもいい話を言ってダメなんですけれども、
- 09:01 ドイツは割とものを定義するのが大好きです。
- 09:05 もしもダメな定義だったとしても定義することによって
- 09:10 話題の統一はできます。
- 09:13 なのでまずは結合がなんなのか定義してみましょう。
- 09:19 一番シンプルな定義だと
- 09:23 ものAがあって、ものBがある。AがあってBがある
- 09:28 Aを変更します。Aを変更したら
- 09:32 Bも変更する必要がある。
- 09:36 その状態は結合
- 09:40 という風に定義しましょう。それが割と正しい気がします。
- 09:47 そしてそれと連携してくる言葉は2つあります。
- 09:52 密結合と疎結合。疎結合は
- 09:59 講演のタイトルにも入っています。密結合は
- 10:04 ある2つのものが結合している状態を表しています。
- 10:08 そして結合していない状態のことを疎結合
- 10:14 と言います。
- 10:19 実はそれをどうやって日本語にするかいろいろと迷ったので、 英語も
- 10:25 のせてみました。英語にすると結合はCouplingになります。
- 10:30 そして密結合は、Tight Coupling
- 10:35 疎結合はLoose Coupling
- 10:38 そして英語とかでよく使うDecoupling、つまり
- 10:44 結合しているものを
- 10:46 分割する。
- 10:47 つまり疎結合にするかな、日本語で言うと。は、Decoupling
- 10:54 って言いますけど、たぶん日本語はそれに該当する言葉がそんなにないかな、分割以外
- 11:00 分離って言ったり
- 11:03 疎結合とかにいったり、いろいろ使ってますけど、Decouplingが
- 11:09 すごくいい感じだと思いますので、とりあえず英語ものせてみました。
- 11:16 そしてこのプレゼンの準備としていろんな人に結合と密結合と疎結合はなんですか
- 11:23 と聞いてみたら
- 11:25 みんなはコードの話しかしていなかった。
- 11:30 実は結合はコードの話だけではないです。
- 11:36 結合はいろんなレベルで発生します。
- 11:40 そのレベルはどういうレベルなのかというと、コード上の結合があります。データの結合もあります。
- 11:49 そしてワークフローの結合もあります。
- 11:53 そして
- 11:56 それは左で右はその影響範囲。 もしもコードが
- 12:03 結合しているのであれば、その結合の影響を受ける人たちはプログラマエンジニアだけです。
- 12:12 もしもデータ上の結合が
- 12:17 よろしくない場合、その結合によって影響を受ける人はエンジニアだけではなく、
- 12:24 デザイナー
- 12:26 であったり、いろんな人です。
- 12:30 そしてワークフローの話になると、プロジェクトに入っている全員に影響がでたりします。
- 12:39 コードレベルの結合は
- 12:43 ゲームロジックは
- 12:45 UIロジックを直接たたく
- 12:48 というのは例えばコード上の結合。
- 12:51 データの結合は例えば、そのゲーム全体は誰もやらないと思うんですけど、
- 12:58 そのゲーム全体を一つのUnityのシーンで管理している。
- 13:02 そうすれば例えば、同じシーンの
- 13:07 編集したい。それができない。
- 13:11 までいったとしても、いい感じのコンフリクトが発生します。
- 13:16 つまりあまりおすすめしない。
- 13:18 そしてワークフローの結合は、例えばAさんがいて、Aさんは企画書を書きます。
- 13:26 そしてBさんは
- 13:28 企画書が出来上がるまで、作業に入らない状態。
- 13:33 その場合は、ワークフロー上の結合が発生しています。
- 13:39 特にプログラマに覚えてほしいのはこれですね。
- 13:44 コードの結合は、データとワークフローの結合に繋がります。
- 13:51 つまりそのコードとかプログラムを設計するときに、気を付けないとエンジニアだけではなく、
- 14:00 プロジェクト全員に
- 14:02 影響が出る
- 14:04 そしてワークフローの効率が落ちる。したがって品質も落ちる。
- 14:11 なので基本的には、それを頭の中に入れてもらえたらうれしいです。
- 14:18 次は
- 14:22 結合するものをどうやって分割するのか
- 14:26 つまりどうやって密結合になっているものを疎結合の道へ運んでいくのか
- 14:32 というと基本的には、手段として抽象化をします。
- 14:38 つまり、抽象化レイヤーを挟んで
- 14:42 それによって
- 14:45 密結合だったものを疎結合にもっていきます。
- 14:51 つまり、左のように直接つながっているものを、
- 14:59 抽象化レイヤーを挟むことによってその結合をなくします。
- 15:07 プログラミングとかゲーム開発と全然関係ないですけど、血液の
- 15:13 関門ってきいたことあります。
- 15:17 聞いたことある人います。
- 15:19 素晴らしいですね。基本的に身体のあちこちに血液が流れていて非常に便利
- 15:26 なんですけど、血液がそのまま脳に流れたりしないというのを
- 15:33 ご存知だった人はいっぱいいるかもしれないです。
- 15:36 つまり、体の中でも
- 15:39 結合が起きる仕組みはいろいろあります。
- 15:42 例えば血液の流れを脳のレベルで切って、脳に入ってくるものを他の部分
- 15:50 と違うようにコントロールしたりします。
- 15:55 結合のレベルと同じように抽象化レベルも
- 16:00 同じようなレベルがあります。
- 16:02 コードレベルの抽象かは可能ですし、
- 16:06 データのレベルでもそうですし、ワークフローのレベルでもそうです。
- 16:12 コードのレベルで言うと、インターフェースというの使ったりというのが一番
- 16:17 わかりやすい気がします。
- 16:19 あとはデータのレベルだと、
- 16:23 一番シンプルなのでは、タスクごとにファイルを切ったり用意したりすることです。
- 16:31 そしてワークフローレベルは正直、
- 16:34 ワークフローのレベルになると、たぶんワークショップができるくらいの内容になるので、
- 16:40 ここでは省略させてください。
- 16:44 割とプロジェクトマネージメント並みの話になりますね。
- 16:53 たぶんちょっとだけ勘違いされる方はいるかもしれないですけど、
- 16:57 抽象かは汎用化でも一般化でもないです。
- 17:04 基本的に抽象化は二つのものを離すためにやるものです。
- 17:12 例えば
- 17:14 データベースがあって、そのデータベースンのAPIを
- 17:18 抽象化したい。つまり直接たたくのではなく、
- 17:22 抽象化のレイヤーを用意したいです。
- 17:25 その場合は
- 17:27 そのデータベースのAPIをそのままインターフェース化するのではなく、
- 17:36 自分たちのケースに合うような、最低限の
- 17:41 抽象化レイヤーをする。
- 17:43 そしてそれを用意する。それが重要です。それをやらないと無駄な行動が発生しますし、
- 17:50 いろいろあとから厄介になる。
- 17:53 そしてたぶん
- 17:57 抽象化と汎用化が一緒になっている肩がいるので、
- 18:02 抽象化とか疎結合とかを聞くと、
- 18:06 すごい
- 18:07 タスク量とか仕事量が増える印象を持っている方がいるかもしれないですけど
- 18:13 実はそうではないです。
- 18:16 疎結合にもっていくのに、最低限のもの、シンプルなものしか用意しない。
- 18:23 そうすることによってあまり、オーバヘッドは発生しないです。
- 18:30 つぎは結合に
- 18:33 バランスがあります。
- 18:37 そしてそのバランスはプロジェクトの規模に依存する。
- 18:44 なぜかというと
- 18:48 すごいちっちゃなプロジェクトの
- 18:52 規模が大きくなると、いろんな要素が入ってきます。
- 18:59 例えば今までなかった要素が新しく入ってきたり、または
- 19:05 すごい小規模なものだったら
- 19:09 それはテストとかデバッグとか
- 19:14 品質保障はそんなに重要じゃないかもしれない。
- 19:18 プロトタイプであったり、どこかのゲームジャムであったり、そんなにいらないですけど、
- 19:22 実際に大型プロダクションに入ると、そこをちゃんとやらないと
- 19:28 痛い目にあうことになったりします。
- 19:33 なので小規模で通用したテクニックが裏目に出たりする。
- 19:39 そしてここのプロジェクトの規模はなにを差しているかというと、
- 19:45 企画のスケールもそうですし、あとはチームのサイズもそうですし、
- 19:52 あとは開発期間
- 19:54 そして特に最近のモバイルゲームとかだと運用期間も
- 20:01 プロジェクトの規模のうちに入ります。
- 20:05 5年間とか10年間もしも同じゲームを運用し続けると、それはそれで規模が
- 20:13 でかくなります。そして、たとえば5年間とか10年間のプロジェクトだと、
- 20:19 ずっと同じメンバーというわけにはいかないので、
- 20:24 もともとのメンバーは
- 20:26 離れる。新しいメンバーが入ってくる。
- 20:31 そして結合によってどのくらいみんなは把握しなければならない
- 20:37 という量が変わったりする。
- 20:40 なので、それを割とでたらめなグラフなんですけれども、
- 20:46 それをグラフにすると基本的にそんな感じになります。
- 20:50 プロジェクトの規模が小さいとぶっちゃけ密結合でもやっちゃえましょう。
- 20:56 なんですけど
- 20:58 そのプロジェクトの規模とともに
- 21:02 疎結合を頑張ってやらないと
- 21:08 こんな感じでいい感じのトリオだったのは、みんな楽譜とかで
- 21:14 つながっててみんなが違う
- 21:16 ちなみにそれを知っている方はいますか。どれも割と有名な
- 21:21 20世紀のクラシックトリオですね。
- 21:27 その3人はよろしくやれてたんですけれども、もしも
- 21:33 お互いの楽器が結合しちゃったり、楽譜が結合しちゃったりすると、
- 21:39 いい感じの3人だったのが、ヒドラに
- 21:43 変身します。
- 21:45 そして ヒドラの一番厄介なところは首を切ると、数が増えるんですよね。
- 21:52 それを英雄だったらそれと戦うのは楽しいんですけど、毎日
- 21:59 戦うことになるとしんどいだけ。
- 22:02 なので、みんなのプロジェクトはそうならないように日々努力する必要があります。
- 22:12 なぜ努力する、結合している、またはそのバランスが崩れている、密結合が多い
- 22:20 何が問題化というと
- 22:23 ほとんどの場合、プログラマもそうですし、デザイナーもそうですし、ある特定なタスクをこなす
- 22:31 というのは主なワークフローになっています。
- 22:34 そしてそのタスクは孤立しているのであれば、
- 22:37 集中しやすい把握しやすい
- 22:41 対応早いなんですけれども、独立しているタスクは
- 22:46 本当はいろんな要素と繋がってしまっているのであれば、
- 22:51 孤立してるタスクをこなすのに、把握しなきゃいけないものがいっぱいあります。
- 22:58 そしてシンプルな対応が大変な対応になる。
- 23:02 本当は問題ないはずなのに、誰も想像のつかないところで、副作用が出たりします。
- 23:12 なのでそういうケースは特に5年間とか10年間の長いプロジェクトだと割と
- 23:20 圧迫していきますね。
- 23:21 そうすれば例えば、新しく入ってきたメンバー が実際にタスクをこなすのに何週間も
- 23:27 全部
- 23:30 把握しなきゃいけなかったりします。すいません日本語やばかったりしますけど、
- 23:37 雰囲気的にそんな感じですね。
- 23:41 まぁ非常にいいのはバランスが崩れても、手遅れではない。
- 23:50 基本的にはバランスが本当は簡単なタスクなのに、すごい大変だと気付いた時に、
- 23:57 密結合が強すぎる。
- 24:01 疎結合にもっていく必要がある。
- 24:04 その時点で計画的に
- 24:07 やっていくと
- 24:10 それでも解決できます。もちろんスケジュールはきつかったりする。
- 24:16 その疎結合にもっていくための
- 24:21 コースは見積もってなかったりします。
- 24:25 それは割と当たり前な話なんですけれども。気付いたときに
- 24:30 見積もりしなおす。計画に入れる。
- 24:34 ちゃんと工数をおさえる。
- 24:36 設計しなおすというのを入れることによって、
- 24:42 バランスが崩れたとしても直したりすることができます。もちろん
- 24:47 そのバランスはいいのか悪いのかは、やってみないとわかんない。そして
- 24:54 もっと重要なのはお互いと話して
- 24:58 みないとわからないです。
- 25:00 なので、その結合はどのくらいがちょうどいいのかというのを判断するのに
- 25:06 そのプロジェクトにかかわっている全員にはお互いコミュニケーションをとらなきゃいけないです。
- 25:12 それはエンジニアが
- 25:15 会議してても解決しなかったりします。
- 25:19 つまりそこは
- 25:20 いろんな
- 25:23 各分野の人たちのコミュニケーションが非常に重要です。
- 25:32 ということで、ちょっとだけ
- 25:35 UIの話に戻りましょう。
- 25:37 そして今からちょっとだけUnityの話と一か所だけテクニカルな内容になります。
- 25:44 もう一回振り返ってみるとこういうワークフローにしたいです。
- 25:49 デザイナーはデザインする。プログラマはプログラミングする。
- 25:54 割と当たり前なことです。
- 25:58 この場合は
- 26:01 大きな問題が一つあります。その問題は同時作業になります。
- 26:06 つまりコンフリクトはあり得ます。
- 26:10 そして同時作業だから
- 26:13 ワークフローのレベルでそのコンフリクトを阻止することはできない。
- 26:19 違うレベルでそのコンフリクトを阻止する必要がある。
- 26:24 Unityの場合は
- 26:26 Unityの場合だけではないです。もしもワークフローで阻止できないのであれば、
- 26:32 一個下のレベル。つまりデータのレベルで阻止できるのか、
- 26:36 検討してUIの場合は、
- 26:40 それができます。つまりUIを制作するときにさっきみたいなワークフローだと、
- 26:46 データを分割することによって、データの分割によってコンフリクトを阻止することができる。
- 26:54 それに従ってもっと下のレベル
- 26:56 コードのレベルはそのデータの分割に対応する必要がある。
- 27:01 そういう意味で
- 27:03 一番上のワークフローをいい感じにするため、下のレベルのデータの修正が必要。
- 27:09 そしてその修正によって、また下のレベルの修正が必要になります。
- 27:15 UIの話で言うと、
- 27:19 ただ単に、ただ単にじゃないです。シーンを分ける。
- 27:27 UnityのシーンのUI用のUnityのシーンを用意する。
- 27:32 そしてそのUIシーンの
- 27:35 所有権を
- 27:37 デザイナーに
- 27:39 与える。
- 27:40 つまりそのUIシーンは
- 27:43 デザイナーが編集します。
- 27:46 そして
- 27:49 プログラマはそのシーンをいじらない。
- 27:52 それによって
- 27:54 同時に作業だったとしてもコンフリクトは発生しない。
- 27:59 従って、ゲームはUIシーンだけで動かないのは当然。
- 28:04 もちろんゲームロジックが存在していったり、他のシーンも存在している
- 28:10 のでこの分割によって発生する問題は
- 28:16 2つのシーンとがシーンと他のシーン
- 28:20 を連携させることによる。
- 28:23 エンジニアは何人くらいですか。手を上げて
- 28:29 ほぼ全員エンジニアですよね。了解です。ここの話は割と省略できると思います。
- 28:38 Unityシリアライズ機能は複数の
- 28:42 シーンだとあまり使えないんですよね。
- 28:48 なんか同じシーンだったら抜群ですし
- 28:51 もしもそのシーンからアセットを参照しているのであれば、完璧なんですけど
- 28:56 あるシーンにあるゲームオブジェクトを他のシーンから参照して
- 29:02 それをシリアライズしようとすると、いろいろ危なかったりする。
- 29:07 なので
- 29:09 その連携はどうやって取らせるのか。Unityの機能はそんなに使えない
- 29:14 ので、データのレベルとかビルドの機能ではなく
- 29:19 下のコードのレベルの対応が必要になります。
- 29:23 その問題を解決するのは
- 29:26 解決するのに、解決方法はいっぱいあるんですけれども、ここでちょっとだけ
- 29:34 述べたいのは主に3つ
- 29:36 MVCとかMVVMそういうUIを作るのに割と一般的な
- 29:42 仕組みでその問題を解決することができます。それは割と大きな
- 29:48 トピックですし、あとはなんか去年のGDCですごいいいセッションがあったので、
- 29:55 ここではそれをスキップして、もしも興味がある方がいらっしゃったらぜひ去年のGDCの
- 30:03 スライドを見ておいてください。
- 30:06 もしもそのMVCとかMVVMも場合によって
- 30:09 オーバーエンジニアリングですので、場合によっては上の方は全然使わなくても
- 30:16 下の2つの方法でいけます。一つの方はUnityEngineに入っている
- 30:22 ExposedReferenceという
- 30:23 機能です。それを聞いたことある方とか、使ったことある方とか、戦ったことある方
- 30:29 います。
- 30:31 あぁ、いますけど割と少ないですよね。
- 30:36 そしてメッセージ・バスという方法もあります。
- 30:41 これからちょっとだけその2つを紹介していきたいです。
- 30:45 そのUnityEngineのExposedReferenceは何かというと、
- 30:51 基本的に
- 30:54 ExposedReferenceはただのIDで
- 30:58 そして実行時に、ランタイム時にそのIDを
- 31:02 特定なテーブルに対してルックアップしてそのIDから実際のインスタンスを取り出す。
- 31:11 その仕組みを使っているのはUnityのタイムライン機能はそうなんです。なのでそれと戦ったことの
- 31:17 ある方はおそらく
- 31:18 タイムラインを拡張したりしたはずです。
- 31:22 なんですけど、タイムラインじゃなくても普通に使えるのは使えます。
- 31:27 そのExposedReferenceの
- 31:30 ルックアップ仕組みなので、
- 31:34 そのExposedReference側でも、ルックアップテーブル側でも
- 31:39 そのIDを管理する必要がある。
- 31:43 というのは
- 31:44 いいところでも悪いところでもある
- 31:48 なので管理しなきゃいけないものが増えます。それを自動化できなかったり
- 31:54 するとそれはそれで
- 31:58 バグの原因になりますね。
- 32:02 ただ単に言うと。なのでもうちょっと違う方向で攻めようとすると、メッセージ・バス
- 32:10 という仕組みがあります。それはパターンとかそういう方だと、オプサーバーパターンの
- 32:17 シグルトっぽい
- 32:19 ものです。
- 32:21 基本的にはそのパターンでいくと、ある情報をメッセージに変換します。そして
- 32:30 そのメッセージをバス、つまり接続に飛ばします。
- 32:37 そしてその接続
- 32:41 その接続する側でそのメッセージを受け取って処理したりします。
- 32:47 そのメッセージ・バスの特徴は
- 32:51 なぜか消しちゃったんですけど
- 32:54 前に私そのスライドに書いてあったはずなんです。
- 32:58 そのメッセージ・バスの特徴は
- 33:01 その発信元は
- 33:05 接続先を知らない。そして接続先も発信元を知らない。
- 33:13 それはオプサーバーパターンとはちょっと違います。
- 33:17 それを実際に
- 33:19 ちょっとだけグラフィティカルに説明しようとするとそんな感じになります。
- 33:25 UIシーンに
- 33:27 一番左みたいなバインディンが
- 33:31 あります。
- 33:33 そして
- 33:34 UIデザイナーはそのバインディングに
- 33:38 ドラッグ&ドロップしたいものをドラッグ&ドロップします。
- 33:42 そうすれば、見た目上はすいません、それは私が作ったUIですので、しょぼすぎてすいません。
- 33:49 こういうUIに該当する。そして、スタートボタンとかEXITボタンは
- 33:56 そのイベントを
- 33:59 メッセージに変換してバスに飛ばして、そしてそのバスに接続している
- 34:06 処理先はそれを任意に処理します。
- 34:10 つまりそのUIのイベントをゲームとつなげる場合は、
- 34:19 下のバスがあります。そしてもちろんゲームの場合は、そのUIをゲームロジックから
- 34:28 制御する必要もあったりします。
- 34:31 その場合は逆に
- 34:33 ゲームロジックであったり、つまり一番右は、
- 34:37 発信元、情報元になって、バスに飛ばして
- 34:43 それを
- 34:45 UIのロジックで管理する。
- 34:47 もちろんここでみんなが気になるのは、そもそもこのコンポーネントは誰が作るのか。そして
- 34:55 そこに入るのは、
- 34:58 そこに入る情報とか飛ばす情報はなんの情報なのか。誰がそれを決めるのかというと
- 35:05 それ一番最初のスライドに戻るんですけれども、
- 35:09 基本的に、デザイナーがいてプログラマはそのサポートをする。
- 35:16 つまりデザイナーとプログラマで
- 35:20 ゲームに飛ばす必要のある情報を洗い出す。
- 35:26 そしてUIだけで
- 35:28 完結するものは
- 35:31 ゲームロジックに飛ばさなくていいので、
- 35:35 UI上で完結するものはUI上で完結させる。
- 35:40 ゲームに流し込む情報だけ
- 35:44 一緒に洗いだして
- 35:48 プログラマはそれにあうようなコンポーネントを用意して
- 35:53 デザイナーはそのコンポーネントを自分のシーンに入れて、バインディングを行う。
- 36:00 もちろんその場合は、完全な分割にはなっていない。
- 36:07 デザイナーがバインドできるものは結局プログラマが作らないといけない。
- 36:13 なんですけど、プログラマが提供しているのはバインディングのデータではなく、
- 36:20 そのバインディングの機能をコードとして提供している。
- 36:23 のでコンフリクトにはならない。
- 36:33 そしてもう一つの
- 36:37 メッセージ・バスのいいところ。
- 36:40 すいません、私がそれを推しているので、もうちょっとアピールさせてください。
- 36:46 メッセージ・バスのアピールするのはさっき言ったように、
- 36:50 発信元は処理元を知らない。処理先。
- 36:55 そして処理先は発信元も知らない。
- 36:58 そして
- 37:00 複数の
- 37:01 発信元がいてもいい、処理元があってもいい
- 37:08 ので
- 37:09 デザイナーは例えばデバッグがしたい。
- 37:12 このテキストに40文字が入るはず。
- 37:18 それを試したい。ゲームは立ち上げたくない。
- 37:22 せっかく独立するシーンになっているので、ゲームと繋げないで確認したい。
- 37:29 その場合はメッセージ・バスだと
- 37:30 例えば今みたいな、今みたいなというかそのタイトルメニューデバッグという
- 37:37 スクリプタブルオブジェクトを
- 37:39 プログラマが用意して
- 37:42 そしてそのUIの動作を
- 37:46 デバッグするのに最低限な機能をそこにつっこむ
- 37:51 そして
- 37:53 どうやってUIと連携させるかというと、メッセージ化してそれを
- 37:58 ゲームのロジックと同じバスにつっこむだけで同じ動きになりますね。
- 38:04 例えばここのStartボタンとEXITボタンを押すと
- 38:08 コンソールにこれを押しましたというのが出たり、
- 38:12 あとはキャプションに入れたもの、お前はもう死んでいる
- 38:17 というのは実際にキャプションになります。
- 38:21 まぁそうすることによって、デバッグもしやすくなる。
- 38:25 そして
- 38:27 デザイナーは自分のUIが動いているかというチェックもできます。
- 38:33 なので例えば実際に
- 38:35 UIは単体で動く
- 38:38 ゲームと連携させる
- 38:40 動かない
- 38:42 原因は
- 38:44 ゲーム側にある
- 38:46 逆の場合、ゲームは大丈夫そう。
- 38:50 UIを単体で試す。動かない。デザイナーがミスった。
- 38:57 というのは簡単にできます。プラス
- 39:01 テストの自動化もできます。つまり単体テストも可能になります。
- 39:08 必要なメッセージを
- 39:10 そのテスト内で飛ばす。
- 39:13 そしてその結果を確認する。
- 39:16 なので、テストの自動化もそうですし、
- 39:20 デバッグもしやすいです。そして実際に特定なもののデバッグができるようになります。
- 39:28 という感じで
- 39:32 もう今日のおさらいに入ります。
- 39:38 ここではとりあえず重要だなと思うポイントを上げていきたいです。
- 39:47 一つ目は結合はコードの話だけではない。データとワークフローでも発生する。
- 39:55 それは非常に重要です。
- 39:58 そして規模とともに疎結合が必要となってくる。
- 40:06 次はコードの結合はデータとワークフローの結合に繋がる。
- 40:12 ので特にプログラマは密結合を選ぶ前に、
- 40:20 2,3回ぐらい考えて、みんなと話し合ってもう一回考えましょう。
- 40:27 疎結合の道は抽象化で開く。
- 40:31 つまり、結合しているものを切り離すのに、その間に抽象過程を挟むことによって
- 40:40 疎結合に見えたりします。
- 40:45 コードとデータの疎結合はよりよいワークフローに繫がる。つまりそのデータが
- 40:54 UIの場合、例えばそのUIが
- 40:58 単体のシーンではなく、
- 41:01 プレハブになっているのであれば、
- 41:04 そのプレハブを
- 41:06 ゲームとつなげるために、どっかのシーンに放り込む必要がある。
- 41:12 そしてその放り込む際は、もしも自動化をやるのであれば、それはプログラマの
- 41:22 課題になる。
- 41:24 もしも
- 41:25 他のプレハブをシーンに放り込むのは自動化せず、
- 41:31 誰かがやるのであれば
- 41:34 デザイナーであったり、プランナーであったり、プログラマであったりはしますけど、
- 41:40 UIのデザイナーではなくなっちゃいます。
- 41:44 それによって
- 41:46 UIデザイナーは本当にUIの制作
- 41:49 そして品質管理単体でできなくなっちゃって、それによってワークフロー上
- 41:56 結合が発生して、
- 41:59 効率が下がったりします。
- 42:02 のでデータを
- 42:04 いい感じに分割することによって
- 42:08 より効率の高い、より品質の高いワークフローに繫がる。
- 42:15 ワークフローは可能になりますね。
- 42:18 あとはUnityにおいて
- 42:22 極端なんですけれども
- 42:24 シーンを
- 42:26 分けることによって
- 42:29 同時作業は非常にやりやすくなったりします。
- 42:34 ので同時に作業できないところは、プレハブとかいろんな
- 42:39 やり方はあるんですけれども、
- 42:41 シーンを分けたりできないんじゃないかなというのを
- 42:44 検討したほうがいいと思います。
- 42:48 そして、複数のシーンやロジックを
- 42:51 疎結合を保ったまま繫げるのに、
- 42:55 メッセージ・バスは
- 42:57 役立ったりします。
- 43:01 そうです。
- 43:04 最後のスライドになるんですけど、まだちょっとだけ時間があるので、ちょっとだけボーナススライドも用意
- 43:11 していますのでちょっとだけ
- 43:13 付き合ってください。みんな帰りたいですかね。
- 43:16 はい、帰りたいのは私だけでした。
- 43:21 あとは忘れる前に、
- 43:26 QAコーナーがあるんですけれども、それはここを右に出てすぐにあります。
- 43:32 昨日私が探してすごい迷ってたんです。
- 43:35 なので、質問がある方は講演のあと、そこで話しちゃいましょう。
- 43:43 じゃあボーナススライドにちょっとだけ入ります。
- 43:48 Rool-a-ballというUnityの初心者チュートリアルって知っている方います。
- 43:55 ありがとうございます。すごい初心者向けのチュートリアル。
- 44:04 チュートリアルなので
- 44:07 初心者の勉強にはちょうどいいんですけれども、
- 44:11 もしもそれを中級者または
- 44:15 上級者としてやるのであれば
- 44:17 何を改善すればいいのか、ちょっとだけ一緒に考えていきたいです。
- 44:21 Rool-a-ballがある。
- 44:23 私はテストを自動化したい。または、MLエージェントを遊ばせたい。
- 44:32 つまり、そのために私がやりたいのは入力元を差し替えたい。
- 44:40 もともとの実数は
- 44:44 こんな風になっています。初心者向けのチュートリアルなのでちょうどいいんですけれども。
- 44:48 このFixedUpdateで入力情報を引っ張ってきます。そして
- 44:54 Unity Engineのインプットからそれを直接引っ張ってきます。それは
- 45:00 やらないでください。もしもプロダクションとかでそれをやると
- 45:08 いろいろデバッグもテストも
- 45:12 いろいろ効率が非常に悪くなるので、こんな風に直接拾ったりはしないでください。
- 45:21 逆に
- 45:23 やりたいのは抽象化レイヤーを挟みたい。
- 45:26 つまりゲームロジックはUnity APIを読んでいたのを、
- 45:32 ゲームロジックがあって抽象化
- 45:35 レイヤーがあって、そしてその抽象化レイヤーでUnity APIを隠ぺいする。
- 45:40 そして逆に抽象化レイヤーのUnity API以外に、例えばマシーナリーのエージェントの
- 45:49 出している入力情報を
- 45:52 同じ抽象化レイヤーを使って流し込んだりする。
- 45:57 それがしたいんですね。一つのパターンはみんなもご存じかと思いますけどちょっとだけ
- 46:02 紹介したいですね。
- 46:04 そういうときによく使うのは
- 46:07 インターフェイス化
- 46:08 つまり、インプットのインターフェイスを用意します。
- 46:13 さっきも
- 46:14 言った通り、抽象化が一般化ではない。
- 46:18 このサンプルで使いたいのは
- 46:23 Horizontal and Vertical Axisだけ
- 46:27 なので
- 46:28 そのケースで用意するインターフェイスはUnityのインプットのAPIを完全に再現するインターフェイスではなく
- 46:37 ストリングを受け取る
- 46:40 インターフェイスでもなく
- 46:42 ちょうど今の場合必要である
- 46:45 情報がとれる
- 46:47 最低限のインターフェイス。この場合はHorizontal Axis and Vertical AxisのGetですね。
- 46:55 そしてそのインターフェイスをもちろんPlayerControllerから呼ぶ必要がある。その場合は
- 47:07 この場合は全然使っていいのはsingletonパターンですね。
- 47:12 つまり
- 47:15 インプット のインターフェイスのインスタンスを一個しか用意しない。
- 47:19 そしてそれをどこからでも
- 47:23 呼べるように、使えるようにします。それはsingletonパターンで、入力の場合は非常に役に立ったりします。
- 47:35 そうすることによって
- 47:42 もう疲れましたね。
- 47:45 入力情報元の差し替えは可能になります。つまりテストの自動化もそうですし
- 47:53 マシーナリーで遊べたりはします。
- 47:59 次のボーナススライドはこれですね。C#における抽象化。
- 48:05 基本的にやり方が大きく2つ分かれています。
- 48:09 インターフェイスを
- 48:13 用意して抽象化するのか、またはイベントベースを抽象化する。
- 48:19 その一番大きな違いはインターフェース化だと
- 48:23 どんなタイミングで、
- 48:25 情報は交換されるのか。
- 48:28 どんなタイミングで情報が
- 48:31 交換されるのは処理側が決める。
- 48:36 この場合だと
- 48:38 処理側はPlayerControllerで、PlayerControllerの任意なタイミングでその情報を取得する。
- 48:47 イベント化にすると、処理側ではなく情報元が
- 48:55 そのやり取りのタイミングを決める。なので、抽象化する場合、
- 49:02 情報元がタイミングを決めた方がいいのか
- 49:06 まずは処理側が決めた方がいいのか
- 49:09 というのを考えてどっちかを選んだほうがいいいと思います。
- 49:15 ゲームだと、そもそも30fpsとか60fpsではしるので、
- 49:21 個人的にはインターフェイス化が好きです。
- 49:25 もしもそれがゲームじゃないとイベント化はいろいろ
- 49:29 便利なんですけれども、そもそも毎フレーム
- 49:33 はしるので、
- 49:35 パ フォーマンスとかが許す限り
- 49:38 任意なタイミングで処理したほうが都合がよかったりする。
- 49:42 ので
- 49:43 インターフェイス化でいけそうだったらインターフェイス化でいきましょう。
- 49:48 そして最後はC#における…もう時間ですね。45分経ったら
- 49:57 合図を送ってくれるという話じゃなかったでしたっけ。すいませんというわけで
- 50:08 C#におけるイベント化
- 50:10 言語レベルで
- 50:11 対応するデディケートイベントみんな知っていると思います。
- 50:15 Unity APIもそれを使っています。非常に便利な隠し機能がいっぱいある。例えばUnity Editorの
- 50:21 EditorApplication.hierarchyChangedは非常に便利だったりします。
- 50:27 以上です。
- 50:29 ありがとうございました。