お疲れ様です!

25卒の渡辺康介と申します。
ゲーム・エンターテイメント事業部(以降SGE)のSGEコア技術本部(以降コアテク)にて「CA Tech Mission」というインターンシップに参加しました。今回の記事では参加までの流れ、開発内容、開発後の感想、生活面での感想をお話ししたいと思います。

拙い文章ですが、読んでいただけるとうれしいです。

 

CA Tech Mission

今回参加した「CA Tech Mission」は、好きなMissionを選び、その目標に向かって開発することができるプログラムです。開発の際には優れたエンジニアの方がトレーナーとしてサポートしてくださり、詳細なフィードバックをいただくことができます。これまでにない成長を実感することができます。

自分は「Unity製の大規模ゲームの開発効率を向上させるためのツールをOSSとして開発・公開」というMissionに参加しました。このMissionにはいくつか開発したいツールの一覧がありましたが、私は「UIデザイナーのUnityにおけるワークフローを効率化するツール」の開発に携わりました。

インターネット上に「CA Tech Mission」の体験談や情報が全くなかったため、応募から参加までのフローについてお話しします。

自分が応募し、合格をいただくまでのフローは以下の通りでした。

  1. ES(エントリーシート)の提出
  2. 面接
  3. 合格

他の就業型インターンである「CA Tech JOB」では、フローの中に人事との面接が含まれていますが、「CA Tech Mission」では人事との面接はありませんでした。面接の際には実際に開発する際にトレーナーをしてくださる方と話します。私の場合は、矢野さんという方と面談をさせていただき、インターンシップ中もずっとお世話になりました。(ありがとうございました)

また、各ミッションごとに個別の応募フローがあります。

全体的に技術に重きを置いたフローであり、ESでもミッション内容に関連する話題を多く盛り込みました。

私は元々話すことが苦手であり、他のインターンシップの人事面接で落ちた経験もありました。今回はYouTubeでCyberAgentの面接動画を視聴し、対策を練りました。

実際の開発では、3ヶ月の期間では完了することができず、1ヶ月延長して取り組みました。結果として、それでも完成しきることはできませんでした。これは、設計の重要性、例えばクラスの命名の重要さを理解していなかったことが大きいと思います。しかし、失敗や成功の過程でこれらの重要性を理解し、自己成長につなげることができたと思っています。

 

実際のMissionに関して

さて、ここから本題に移らせてください。
「Smart UI Binder」(名称は仮です) というOSSを途中まで開発しました。このツールは、先ほども紹介した通り「UIデザイナーのUnityにおけるワークフローを効率化するツール」というテーマに基づいて考えられたものです。

簡単にツールの概要を説明します。通常、UIを作成する際には以下のようなワークフローが発生すると思います。

 

  1. デザイナーがデザインを考える
  2. デザインをエンジニアに渡してゲームに組み込む
  3. デザイナーがデザインの修正を行う
  4. エンジニアが修正内容を組み込む
  5. デザイナーに渡して…

 

このようなバケツリレーが発生します。UIは開発するうえでモデルやプレゼンターと関わりがあり、スクリプトを記述する必要があります。今回のツールは、この手間を改善するために開発されました。具体的には、以下のようなワークフローに変化します。

 

  1. デザイナーがデザインを考える
  2. Unity上でSmart UI Binderを使用してUIを作成
  3. UIの挙動をダミーデータ等を利用し確認(もしくはバインド部分のみエンジニアがやる)
  4. デザイナーが修正を行う…

 

といった手順です。一部手を借りるかもしれませんが、エンジニアの支援なしにUIを実装することができます。さらに、UIの挙動を自由に変更するための機能として、ノードベースのビジュアルスクリプティングも実装しました。

HPが3割を切ったらHPバーを赤くする、とかクリア数が一定を超えたら獲得ボタンをアクティブにするとか、こういったスクリプトなしでは実現できないものをノーコードで実装することができます。

以上がSmartUIBinderの簡単な説明となります。

続いて開発したものの詳細に関して説明します。

 

コードの自動生成

Smart UI Binderを利用するにあたって、使用したい変数や型が列挙されているBlackboardというスクリプトを自動生成します。Blackboard内の変数は、UIの値を変更するために使用されます。

Blackboardはスクリプトとして存在するため、コードを記述する必要があります。そのため、ノーコードで自動生成できる仕組みが必要でした。今回は、T4 Text Templateというテンプレートエンジンを使用して自動生成を行いました。

具体的な使用方法は以下のようになります。

1.作成したいスクリプトの準備

作成したいスクリプトの準備

 

2.テンプレートの用意

テンプレートの用意

 

3.Unityのエディター拡張を使用して生成の実行

スクリプト生成を実行する手段はいろいろとありますが、今回は以下のようにエディター拡張にのせました。

Unityのエディター拡張を使用して生成の実行

自動生成されたコードの一例は以下です。

自動生成されたコードの一例

 

コードの自動生成にはSource Generatorというツールも存在しますが、その制約としてスクリプトのコンパイル後に生成されるという点があります(これは特徴でもあります)。今回は、ボタンを押した際にスクリプトを生成するという仕様でしたので、自由にタイミングを選択できるT4 Text Templateを使用しました。

また、コアテクのLT会という場でコードの自動生成について話す機会をいただきました。スライド作成でもたくさんのフィードバックをいただき、よりよい発表になったと思います。

以上がコードの自動生成に関する概要です。

 

ビジュアルスクリプティング

冒頭でもお伝えした通り、ノードベースでUIの挙動を編集できる機能を実装しました。ビューはUnityのVisual Scripting(元Bolt)やShader Graphといったものに近いものです。

実装した機能について一部をご紹介いたします。

実装した機能について一部

 

上記の例では、RewardCountと100を比較して、NoまたはOkという結果を出力します。
例えば、HPが3割以下の場合にゲージを赤く表示し、3割以上の場合に緑に表示するといった操作がノーコードで実現できます。

具体的な実装においては、型の変換に苦労しました。グラフ上で作成したノードはデータとして存在し、実行するまで中身が明確になりません。そのため、どの型からどの型にキャストすべきか判断することが難しくなります。上記のグラフでは最終的にStringからStringとなる結果ですが、実行時に初めて型が判明するため、型のキャストやデータの変換を行うためのConvertノードを設けました。

以上がビジュアルスクリプティングに関する概要です。

 

設計

OSS開発を通して設計の重要性を学びました。
開発前、オブジェクト指向やSOLID原則といった概念の価値を理解していませんでした。手続き的なコードでばかり実装していたからです。そのため、OSSとしてのクオリティを十分に満たせるコードを書くことはできませんでした。

設計を怠ると何がまずいのでしょうか?
開発していく中で、設計に関する間違いを何個か犯し、その都度学んでいったのでいくつか話させてください。

1. staticと神クラス

実際の開発では、土台的な設計はもうすでに完成されており、そこに機能を付け足していくフローで進められました。最初の間違いをこの機能を付け足す部分で犯しました。当然、機能を付け足すわけなのでクラスを分けます。ここまではよかったのですが、分けたクラスをstaticにしてしまいました。
クラスをstaticにするとインスタンス化せずにクラス内のメソッドを実行することができます。そのためかなり便利に思えますが、一方でオブジェクト指向の基本的な考え方からは一部逸脱する可能性があります。オブジェクト指向のメリットである再利用性や保守性の利点を完全に享受できないためです。
また、機能の大部分を1つのクラスに集中させてしまったため、どんどんクラス内がカオスになっていきました。こういった余りにも多くの機能性をもつクラスを神クラスと呼びます。

フィードバックの際に、設計の見本を考えていただき、何がダメなのか理解することができました。実際に改善することで、クラス間のつながりが明確になったり、そもそものメリットである再利用性や保守性が向上することに気づきました。

2. わけのわからないクラス名

次の間違いはクラス名をクラス内の処理と乖離があるものにしてしまった点です。
例えば “ScriptGenerator” というクラスがあったとします。中の処理ではスクリプトが生成されるだけだと思うはずです。ですが、実際はスクリプトの内容文を作成し、スクリプトを生成し、自動でゲームオブジェクトにアタッチされるものでした。こうなってくると、“ScriptGenerator”クラスを使う人は絶対にわからないと思いますし、影響範囲が大きくなる都合仕様変更に弱いつくりとなってしまいます。また、処理が分散することで低凝集にもつながります。
そうならないために、各クラスが一貫性のある責任を持つ設計にすることが重要です。この原則は、オブジェクト指向設計のSOLID原則の一つである単一責任の原則(Single Responsibility Principle)に基づいています。
例えば、上記の、スクリプトの内容文を作成し、スクリプトを生成し、自動でゲームオブジェクトにアタッチされるという処理を実装したいのであれば
“ScriptContent”、“ScriptGenerator”、“ScriptAutoAttacher” 等に処理を分割すると良いだろうと言ったものです。(“ScriptContent”は生成部分と内容部分で分割すべきかもしれませんが…)
こうすることで、影響範囲をそのクラスのみに限定させることができ、仕様変更につよいつくりとすることができます。
クラスを責務が1つであることを意識しながら命名することで、こういった乖離を防ぐことができます。

こちらも、フィードバックの際にクラス名を考えることを意識するとよいと指摘され、気づくことができました。実際に責務が1つになるように命名することで、クラス設計全体の見通しがよくなりました。今でも、クラス命名はかなり悩むことが多く、責務が1つに定まらないことから設計全体のミスにも気づくことがあるのでかなり重要な点だと思っています。

3. デザインパターンは目的ではなく手段でしかない

これは、フィードバックで気づいたことではなく、設計に関して重要だと思った考えで、完全に蛇足になりますが書かせてください。

デザインパターンは、車輪を再開発せずに再利用可能な設計を提供してくれ、オブジェクト指向プログラミングの生産性や信頼性を高めてくれます。しかし、デザインパターンはあくまでも「手段」であり、「目的」ではありません。

例えば、SingletonパターンはUnityにとってよく知られたパターンであると思います。多くの場合、“〇〇Manager”クラスで使用されると思います。とても便利だと思いますし、そうすべきシチュエーションも多いと思います。しかし、Singletonパターンを使うことが本当に最善なのでしょうか。例えば、そのクラスがあまりにも多くの依存関係を負うようになると、それは「神クラス」になるという間違いを犯すことになります。よくある“”GameManager”がこれに当たると思います。これはデザインパターンを使用することで得られるメリットに反しており、Singletonパターンに頼りすぎた結果であると思います。

ゲームを個人開発をしていた際も便利さ故、使用していました。ですが、設計に関して意識し始めたことで依存関係の多さから悪手だと気づきました。もし、使うのであればManagerクラスを複数用意しクラス関係を分散するなどSingletonパターンをあくまで参考に手段として使うことが良いと考えています。

今回の経験では、ツール単位で設計の重要性を実感することができましたが、ゲーム全体の設計についてはまだ意識できていません。次回の開発では、オブジェクト指向やDDD(ドメイン駆動設計)を意識して設計に取り組みたいと考えています。

 

生活面

生活面ではいくつかの失敗がありましたので、その中の一つを話させてください。
自宅がAbema Towersから少し遠かった都合で、インターン開始時に人事の方にホテルの手配をしていただきました。しかし、始まってみるとホテルでの生活になじむことが難しく、体調を崩してしまいました。結局、自宅から通う方針に切り替えていただき、無事インターンを完遂することができました。
最初から無理だとわかっていた場合は、何度も通勤方法を変更していただく必要はなかったと思っています。自分の環境変化に対する予測ができていなかったことが失敗の原因だと思っており反省しています。
人事の方々には大変お世話になりました。本当にありがとうございました。
体調面でも気をつけていこうと思います。

 

最後に

ここまで、「CA Tech Mission」で行ったことや学んだことを紹介しました。1つのツールの設計から実装まで関わることができました。最初から最後までサポートしていただいた矢野さんに心から感謝申し上げます。実装の際の学びも重要ですが、設計についての学びこそ、今回のインターンの価値があると思っています。さまざまな課題がありましたが、その都度失敗を繰り返し、多くのことを学ぶことができました。
今後もさらなる成長を続け、さらなる技術の向上に取り組んでいきたいと思っています。

最後まで読んでいただきありがとうございました!