平井 佑樹

ログレスマップエディタのパフォーマンスを改善したお話


はじめまして、17年度新卒エンジニアの平井です。

今回、新卒エンジニアの平井と西田の二人がパフォーマンス向上のため新たにUnityでマップエディタを開発しました。
その際に改善した点や苦労した点を紹介しようと思います。

マップエディタとは

弊社の「剣と魔法のログレス いにしえの女神」及び「ブラウザ版 剣と魔法のログレス」では、自社GUIツールを使用してマップデータを制作しています。地面タイルの配置や噴水などのオブジェクトを配置するだけでなく、キャラクターが移動できない位置の指定や影の設定など、マップ処理に関する様々な設定も可能です。

~新マップエディタ画面~

ログレスの旧マップエディタは、Adobe AIRで作られています。これは、先に開発されたブラウザ版ログレスがFlashで作られているため、マップ上に配置されたオブジェクトを表示したりアニメーションをしたりするためのコンポーネント群を、ゲームクライアントとマップエディターとで共有ができ、開発効率が高いためです。

旧マップエディタの問題点

旧マップエディタは以下の問題がありました。

  • ファイル読み込みに時間がかかる
  • 描画速度が遅い
  • 弊社でAdobe AIRを使えるエンジニアが少なくメンテナンス性が低い

新マップエディタでは、これらの問題を改善することが目標となります。

Unityで開発した理由

  • 弊社には Unity を使えるエンジニアが多くメンテナンス性が向上できる
  • 弊社が Unity を使った開発を活発に行なっており、情報収集が容易かつノウハウを蓄積できる
  • 新卒エンジニアとして Unity を覚えて基本的な開発方法を知っておきたい、使えるようになっておきたい

今回、Unityのエディタ拡張は行わずツールアプリとして運用します。
Unityのエディタ拡張を使わない理由は、マップデザイナーが新マップエディタを使う際に
旧マップエディタと同じ操作感に近づけるためです。

目標

  • 旧マップエディタの機能を再現
  • パフォーマンス改善

これらの目標を達成するために苦労した部分や工夫した部分を解説していきたいと思います。

旧マップエディタの機能を再現

基本的な配置機能は問題なく実現できました。
しかし、旧マップエディタはFlash固有の機能を使って表現している部分があり、Unityのスプライト標準機能では表現できませんでした。

これを解決するためにUnityのシェーダー機能を使って表現しました。

~マスクブレンド~

~カラーブレンド~

ここまでは順調に開発できましたが、Unityで開発していくにあたってパフォーマンス周りの問題が発生しました。

パフォーマンス改善

  • マップファイルの読み込みに時間がかかる

ログレスの標準のマップは平均で10万個のチップやオブジェクトが配置されています。新マップエディタではUnityのGameObjectを10万個作成すると処理が重くなるため、カメラに映し出される箇所のGameObjectのみ生成し、それ以外はデータだけ保持するようにしました。それにより従来6分かかったマップを1分足らずで展開することが出来ました。

  • 描画速度が遅い

マップを読み込み時にチップやオブジェクト(GameObject)をインスタンス化した際にマテリアルも複製されていたためドローコールが増えていました。そのため、インスタンス化する際、1つのマテリアルでチップやオブジェクトを生成して、そのマテリアルのテクスチャを差し替えることで800ぐらいあったドローコールを20~30にまで削減しました。
さらに、カメラに映し出される部分のみチップを生成し、画面スクロールした際、そのチップのテクスチャのみ変更して最小限のGameObjectで描画できるようにしました。その結果、マップ読み込み時のチップ生成速度や描画速度が向上し、スムーズな視点移動が出来るようになりました。

結果

旧マップエディタでも上記の最適化は行われていましたが、平均で20~30FPSしか出ませんでした。しかし、新マップエディタでは常時60FPSを維持することが出来、描画速度の改善を達成できました。

~カメラに映る画面~

~カメラの範囲外のオブジェクト~

まとめ

旧マップエディタと比べてパフォーマンスが向上し、より快適にマップ制作が出来るようになったと思います。Unityで制作したため今後のメンテナンス性はAdobe AIRと比べてかなり上がり、今後の要望にも迅速に対応できるようになりました。

振り返り

Unityを使ったことによりプロトタイプを早く作成することが出来ました。
処理の最適化をする際にとても苦労しましたが、今思えばどうすれば処理を軽くできるかを試行錯誤して、とても良い経験になったと思います。
マップエディタを作るにあたり、どうすれば使いやすいのかを、もう一人の新卒メンバーの西田さんや先輩と話し合いながら取り組みました。
新マップエディタの制作で得た経験を、今後の業務に活かしていきたいと思っています。

ありがとうございました。


mori

HALインターンシップレポート(大阪スタジオ編)後編


こんにちは。人事の森です。

前編に続きまして、「HALインターンシップ」後編では、素晴らしい活躍を見せてくれた3チームの各リーダーに突撃インタビューを行いましたので、その様子をお送りします。

 

まずは、リーダーの紹介。

向かって左から、

  • Aチーム「Dengeon」:岡野 浩之さん(HAL名古屋)
  • Bチーム「コウモリたちのバッドディ」:横山 慈永さん(HAL名古屋)
  • Cチーム「キツネットワーク」:蒲生 大地さん(HAL大阪)

 

こちらの爽やかなお三人が様々答えてくれました。

 

(HALインターン リーダーインタビュー) ※敬称略

 

森:まずは、Aimingのインターンに参加しようと思った理由を教えて下さい。

・・・すごく緊張気味の3人ですが、まずは岡野くんから・・・!

 

岡野:僕はHAL名古屋から来てますが、HAL名古屋は先生からの紹介によってAimingさんを勧められました。僕のインターン先がAimingと知って、テンションあがりました。ログレスをやっていたので、とても嬉しかったです。

横山:僕はAimingのことはよく知らなかったですが、スマホゲームの会社だと聞いて嬉しかったです。最先端の開発を知ることが出来ると思いました。

蒲生:僕はHAL大阪で、HAL専科(夜間に行われる特別ゼミのような授業)でAimingさんの授業を受けていたので、Aimingのことはよく知っていました。そこで働く人達にとても興味を持ったので、インターンに行きたいと思い応募しました。

 

・・・Aimingは、HAL大阪で「専科」を受け持っています。「オンラインゲームプランニング専科」や「オンラインゲーム開発専科」など。蒲生君はプランニング専科の受講生でした。

 

森:3人はどうしてリーダーになったのですか?

全員:皆の推薦です。(全員一致)

 

森:Aimingでは、チーム開発を行う上で、「リーダー/リーダーシップ」は非常に大切なものだと思っています。社内では、随所でこの力が重要視されます。皆さんはリーダーって何だと思いますか?心掛けてることとかあったら教えて下さい。

岡野:皆を引っ張っていきながらも、前に出すぎるのではなくて、共に歩きながら肩を組み、周囲を鼓舞することを心掛けていました。リーダーはすごく有能な人じゃなくても出来るんだ、と思うようにしています。飛び抜けた技術がなくても、コミュニケーションをしっかりとることでリーダーシップを発揮しようと思いました。

横山:制作は終わりが見えないこともある。リーダーとは、「闇を払っていく役割」と思います。他の人を置いてけぼりにしてはいけない。

森:リーダーは「闇を払っていく」役割。良い言葉ですね。(闇を駆けるコウモリとかかっているいるのかしら・・・?) ※以下参照画像。

 

蒲生:チームメイトの仲を保つこと。今回のインターンでは、HAL名古屋の人は、大阪勢より人数が少ないので、肩身の狭い思いをさせないように気を付けました。そして、納期を守ることを厳守しようと思いました。過去に、クオリティを上げる事に必死になり納期を守らなかった経験があるので、その反省が元になっています。

森:Cチームの進捗報告、素晴らしかったです。あと何が残っているのか、この先の展望と合せて説明されていて、とても良かったです。

 

森:1ヵ月過ごした中で、「面白かった」ことを教えて下さい。

蒲生:学校でもチーム開発は経験していますが、ここに来てる人達はモチベーションが元々高いので、何もかもがスムーズだったことです。人生で1番楽しいチーム開発でした。チームメンバーの頑張りで、新技術を取り入れることも出来たし、たくさんのチャレンジがありました。

横山:リーダーを経験できたことです。リーダー経験は初めてではないですが、チーム全体のSlackの会話を俯瞰して眺めるようにしたり、全体把握に努めました。

 

森:では逆に、開発中に1番苦労したことはなんですか?

岡野:UNETの勉強が難しかったです。初めて触ったので、進捗が上手くいかず、何も出来ない状態が最初の1週間続きました。間に合うのかな・・と不安になりましたが、上手くいって本当に良かったです。他にはネットワークの環境構築やエフェクト、アニメーションの作成も、「苦労」とは違いますが、頑張りました。

横山:企画が決まるのが遅く、コンセプトを練るのに苦労しました。制作では、結合する時にバグが発生してしまい、バグをとったらまた別のバグが出る・・・これは大変でした。エンジニア全員でPhotonの勉強をやったことも印象的です。

蒲生:企画が2週目の水曜日まで決まらなかったので、エンジニアに負担をかけてしまいました。HALではまだネットワークをやっていないので、Photonを初めてやったし、Sub versionを触るのも初めてでした。初めてのことは大変ですが、インターンを通して学べたことは大きいです。

・・・初めての経験を試行錯誤してちゃんと成果物として完成できた、素晴らしい・・・!

 

森:幾つか行ったグループワークはいかがでしたか?

岡野:紙飛行機のワークショップが印象に残ってます。丸めて飛ばしたのは僕のチームですが、飛びはしたけど、「品質としてはお客様に出せないよね」と言われたのが気付きでした。思考錯誤の過程も面白かったです。ログレスディスカッションは、緊張して頭真っ白だった。記憶がないです(笑)

横山:マシュマロチャレンジや紙飛行機のように、ルールを初めて知り、限られたツールや時間の中で実施する体験は初めてでしたが、発想力を持ってチームワークで改良してくのが楽しかった。

・・・チームワークで見事に改良した結果がこの笑顔^^
蒲生:僕も、紙飛行機チャレンジが印象的です。クオリティを求めすぎて、求められてるのは「3メートル以上飛ぶことを量産する」なのに、6メートル以上飛ぶことを誇ってしまった。他には、見積もりと結果という考え方や、固定概念に囚われないこと等、「なるほど」と思うことが多かったです。

・・・これですよね。めちゃくちゃ飛んでましたよね。歓喜の声が響いてました。

 

 

森:Aimingのスタッフ(主にメンターさん)と交流しての印象を聞かせて下さい。
蒲生:とにかく「優しい!」です。先程褒めて頂いたタスク管理の方法は、メンターさんに教わったんです。すごく参考にしました。ホワイトボードに アナログトレロを書いて「タスクの見える化」を教えてくれたのもメンターさんです。見える化は凄く大事。身をもって知りました。これを取入れてから、開発が一気にスムーズになりました。メンターさんは自分より年が3つだけ上とは思えない程、しっかりしている。何か相談したら、最初に必ず「それ分かる」って共感してくれるんです。この言葉にすごく安心しました(笑)

横山:メンターが自分たちを信頼してくれてると感じました。お母さんが息子を見るような温かい目で見てくれました(笑)気軽に沢山のことを相談させて頂きました。

 

・・・試遊会では、ディレクターがゲームの感想を伝えます。メンターも同席し、フィードバックを確認。真剣そのものです。

 

岡野:色んな指導の仕方があるのだということを知りました。厳し目なお言葉も貰いましたし、成果物を見て褒めてもくれました。砂漠とオアシスを両方持っていて、締める所はちゃんと締めてくれてる。厳しさとやさしさを併せ持っている印象です。

 

森:何かしらの成長がありましたか?

全員:YES!

・・・最後の言葉、「YES!」を聞いて、私たちも心底「よかった」といえるインターンシップでした。参加してくれた学生の皆さん、1ヵ月本当にお疲れ様でした。

 

 

(まとめ)

1ヵ月を通して、皆個々にチャレンジがあり、成長を実感できる体験が出来たとの言葉、何より嬉しく思います。3チームともに素晴らしかったのは「チームワーク」。リーダーに協力しようという姿勢があり、リーダーはメンバーを思いやる心があり、終始明るい雰囲気のまま進行しました。また、インタビュー中には「メンターさんが厳しい言葉をくれた」との回答がありましたが、該当メンターは入社1年目の新卒スタッフ。後輩が出来、指導する立場となってその難しさに直面し、言わなくてはいけないという責任感から出た言葉なので信頼関係が生まれる。こちらにとってよい学びの機会となりました。

 

 

・・・こちらの写真↑ Bチームメンバーと、一昨年にこのHALインターンのメンターを努めてくれたAimingスタッフの姿も。昨年メンターを努めたスタッフが、翌年にはメンターさんのアドバイザー的なポジションとして、順繰りに後輩をサポートしていく仕組みがあります。

 

Aimingでは通年を通して多くの職種でインターンシップを受入れています。広々スペースで思い切り議論し、物作りに没頭することが出来ます!カリキュラムやスケジュールは柔軟に対応していますので、興味ある皆様、エントリーお待ちしています。

 

 

(おまけ)

 

最終日の打上げにて。多くのAimingスタッフも参加し、盛り上がりました。

 

 

             ★皆さんの未来に乾杯★

 

(完)

 

 


mori

HALインターンシップレポート(大阪スタジオ編)前編


こんにちは。人事の森です。

今日は、毎年恒例、大阪スタジオ10月の風物詩でもある「HALインターンシップ」について書きたいと思います。

大阪スタジオでは、HAL大阪とHAL名古屋から総勢24名の学生さんにお越し頂き、今季増床したばかりのオフィススペースを使ってインターンシップを行いました。広々としたスペースなので、活発な議論を交えながら伸び伸びと制作活動を行うことが出来たと思います。

今年のテーマは「伝える」「伝える」をテーマにしたゲームを制作してもらいます。24名をA、B、Cの3チームに分け、ゲーム制作を行います。1チームの内訳は、エンジニア4、プランナー3、デザイナー1。なかなか良いバランスではないでしょうか。
さて、3チームから、どんな「伝える」ゲームが生まれるのか・・・楽しみしかありません。

インターン生のフォロー体制としては、管理者やアドバイザーの他、最もインターン生と身近に接する「メンターさん」を任命します。このメンター任務を任されたのは、入社1年目の新卒エンジニア、新卒デザイナー、2年目のプランナーが2名という4人の若者達。彼らにとっても、学生を指導することで学びや気づき等、得るものがあることを期待して、インターンシップは始まりました。

 

1ヵ月という、長くて短いこの期間中に詰め込んだミッションやカリキュラムはざっと以下の通りです。

  • 「伝える」をテーマにゲームを制作(メイン)
  • 「中間発表」「最終発表」「Aimingディレクター試遊会」「Aimingスタッフ試遊会」による4段階のフィードバック(これも大事)
  • PDCAサイクルやチームワークの活用に着目したグループワーク(盛り上がりました)
  • 「ログレス」を分解するグループディスカッション(ログレスディレクターを前に、緊張で記憶がないという子がいました)

 

↓ ディレクターやメンターによる試遊会。思いがけないバグも発見されました。

 

↓ スプリント中に、「3メートル以上飛ぶ紙ヒコーキを幾つ生産できるか」というグループワーク。PDCAを上手く回して、チームで紙ヒコーキを作ります、飛ばします、そして数えてまた作ります。かなり忙しくスプリントを回していきます。

 

こ、これは・・・! 紙くず・・・? ゴミ・・? いや、紙ヒコーキ・・?

驚異的な数が3メートルを超えていますが、これを「紙ヒコーキです」とお客様に出すことはで出来ないでしょう。「紙ヒコーキ」の固定概念に囚われない姿勢は良いかもしれません。

 

 

それでは、1ヵ月の成果であるゲーム作品を、それぞれ簡単に紹介したいと思います。

 

まずはAチームから・・・

「Dengeon-美女と呪いの冒険」 

 

「伝達」の「デン」+「ダンジョン」=「デンジョン!」ピクトグラム(絵文字)によって「伝える」をデザインした最大4人同時プレイのマルチプレイヤーローグライクゲーム。
画面構成はサイドビューで、基本的にキャラクターの移動やバトルは自動で進行していきます。そこでこのゲームの肝となるのが絵の伝達というものです。(出た!伝える!)

各プレイヤー毎に示された異なるピクトグラムを全員が同時にお絵描き板に描く。そのピクトグラムを伝えあうことで、扉の先に待ち受けている様々な要素を推測していきます。その推測結果を元に有利な道を選択し、体力の回復、強力な武器の取得などを重ね、最終的にはボスを倒せればゲームクリアーとなります。
ローグライクというランダム要素がベースにありながらも、情報を的確に伝達することで最適な道を選択できる!ですが、お絵かきには時間制限があるので、うまく伝えられない時は、ランダム性による不安定なゲームプレイになってしまうという、何とも絶妙なこの塩梅がこのゲームの面白いところです。

 

 

続いて、Bチームは、ホラーゲームが好きなメンバーによる

「コウモリたちのバッドディ」

最終発表会は、10月31日。つまり「ハロウイン」です。季節感にちなんだ作品を制作するなんて乙だなぁと感想を述べたところ、それは関係ないとのこと。でもコウモリがパンツ履いていて可愛いので問題ありません。

このゲームは、3人 vs 1人の4人同時プレイ、鬼ごっこタイプのマルチプレイヤーホラーアクションです。3人チームのコウモリ側と、1人のコウモリ駆除ロボット側に分かれてゲームをスタート!

逃げるコウモリ、追いかけるロボット・・・まさしくホラーです!でも赤や黄色のパンツがとってもキュート。

 

コウモリ側はマップに散らばった脱出用アイテムの歯車を一定数集め脱出すると勝利になります。また、一定時間以上逃げ延びても勝利です。(私はひたすら逃げ延び、そして勝利しました・・・!)

ロボットは制限時間内にコウモリを全て捕まえると勝利です。
コウモリは、暗闇の中、音波を飛ばして壁に反射させることでマッピングを行い視覚化することが出来ます。また、その視覚化したマップ情報をコウモリチーム間で共有し、これを脱出に活用します。(出た!伝える!)
ロボットは高性能なので自身が出した音と、さらにコウモリの音波もキャッチして有利にマップを走破できます。
暗い工場という不気味なマップの中を追われる恐怖と、追い詰め捕まえるという緊張感を味わうことができるゲームです。(でもカラフルなパンツがキュートです。)

 

最後はCチーム

「きつねっとわーく」

プレゼンがとっても上手なCチーム。発表会では、まるで自社商品を売り込むかのようなプレゼンで、私も思わず「早く遊びたい!」と言ってしまいました。チュートリアルもゲームプレイしながら体験できるようになっていて、とても分かりやすかったです。

このゲームは、3人同時プレイのマルチプレイヤープラットフォームアクションです。プレイヤーはそれぞれのキツネを操作して、全員でゴールとなる鳥居を目指して走ります。キツネにはそれぞれ、「目の良いキツネ」、「鼻の良いキツネ」、「耳の良いキツネ」と能力が割り振られており、その能力で道中に仕掛けられた様々な罠を発見することができます。

ですが、各キツネには1つの能力しか割り振られていないので、自分に分かる罠は他の2人では気付くことができません。そこで「いいね!」と「危険!」の2つのエモーションを使って罠や、見えない床の存在などを知らせる必要があります。(出た!伝える!)
コミュニケーションに使えるのは2つのエモーションのみなので危機の伝達を行うものの、上手くいかないこともあります。時にはジャンプや左右への移動などの身振りも合わせてコミュニケーションを模索しますが、上手く伝わったり、伝わらなかったりと、何とも言えないもどかしさがあります。これを開発チームは演出したかったのでしょう。このもどかしさが意外な程に心地よく、ワイワイと盛り上がる要素になっていて、パーティゲームとしてもとても楽しめました。(私は、「もう1回だけ」と言いながら何回もプレイさせてもらいました!)

 

(まとめ)

それぞれに個性の光る「伝える」ゲームが完成しました。フィードバックの場では、鋭い指摘やアドバイスをたくさん受ける場面がありましたが、落ち込む素振りもなく、真剣に意見を吸収しようとする姿勢がとても印象的です。今年のインターンは、3チームともに「チームワーク」が素晴らしかったです。

いつも、インターンの開発現場に入ると、元気いっぱいに「おはようございます!!」「お疲れ様です!!」。そんな元気な挨拶から始まり、最後は「ありがとうございました!!!」と、これまた気持ちの良いご挨拶を下さりました。

些細なことかもしれませんが、こんな元気な挨拶は、チームだけでなくインターン全体の雰囲気を明るく前向きに動かし、チームワークの醸成を促し、良いゲーム作り、チーム作りに繋がっていくのではないかと感じました。

次回、後編では、この3チームそれぞれのチームリーダーに、1ヵ月間を振返っての直撃インタビューを行いましたので、その様子をレポートします。

 

(おまけ)

最後は皆で記念撮影。賑やかだったスペースが静かになって少し寂しいです(´;ω;`)

 

皆さん、お疲れ様でした。後編に続く。

 

 

 

 


mori

専門学校HAL×Aiming 産学連携プロジェクト(後編)


こんにちは、人事の森です。

前編に続き、「HAL×Aiming産学連携プロジェクト」後編をお送りします。

今回は、栄えある優秀賞を受賞した2作品を紹介させて下さい。優秀賞は当初、1作品のみを選出する予定でした。ところが、どちらの作品も系統が異なりとても面白い!吟味した結果、2作品共に優秀賞を授与する形となりました。

優秀賞受賞作品は、Aiming名義で、App StoreとGoogle Playでリリースします。

それでは、2つの作品を紹介させて頂きます。

 

まずは1つ目、こちらはHAL大阪チームの作品です。

優秀賞:クレイジーヘッドボーイズ(HAL大阪:it OKASHI!チーム)

 

キュートでポップな二人のキャラクターが頭をぶつけながら疾走する爽快感あふれるラン&ジャンプアクションゲームです。

  • タップでジャンプというシンプルな操作だが、画面の上下にプレイヤーを置くことで、良い意味での複雑なゲームデザインが構築されている
  • ゲーム開始までのタップ数が少なく、迷うことなくプレイ開始に誘導している
  • チュートリアルから体感型レベルデザインが組み込まれていて、失敗を通じて正解を模索させるような作りになっている
  • 骨太なアクションゲームに仕上がっていて、しっかりと遊べる
  • ビジュアルにも力入れている

 

カメラアングルも独自性があり、この効果によりスピード感が倍増しているように感じます。こちらの操作方法で、上手くいった時、墜落しちゃった時を実感できるので、「もう1回!」と何度もプレイしたくなりました。キャラクターが可愛いのも良い感じ。Sランクを取るのは非常に難しく、テクニックが必要です。私は未だそこに到達していません。どなたか、タイムアタックで勝負しませんか?

ダウンロードはこちらから。

App Store からダウンロードGoogle Play で手に入れよう

 

 

 

 

続いてHAL東京チームの作品

 

優秀賞:挟撃のインターポーザー(HAL東京:雨霧工房チーム)

個性的なキャラクターが多数登場し、敵を挟んで倒すというやりごたえのある戦略性がおすすめポイントです。

  • はさみ将棋に、独自の世界観とキャラクター性を上手に融合させている
  • ターンベースの詰め将棋といったプレイフィール
  • 見た目とは裏腹に、手応えのある難易度に調整してあり、しっかりと考えないと攻略できないというのが秀逸
  • リプレイ性が高い
  • ステージボリュームが豊富で倍速機能もついている(気遣いが良い感じ!)

 

アプリ内課金の要素はないものの、商用ゲームさながらのまとまりがあり、とても完成度の高いゲームです。クラシカルな内容に、演出とイラストが見事に彩りを与えています。ステージごとに満点をとるのは難しく、満点をとるために熱中してプレイしてしまいました。「挟撃のインターポーザー」というネーミングも素敵です。ゲーム内に漂うラノベ的な雰囲気も、このタイトルに上手く表現されていると思います。

ダウンロードはこちらから。

App Store からダウンロードGoogle Play で手に入れよう

 

 

 

いかがでしょうか・・・?2作品共に短期間の開発ながら非常に完成度が高く、楽しく遊べるゲームに仕上がっています。それぞれ配信期間は、2018年3月31日までを予定していますが、落し切りのゲームなので、DLしてしまえば配信期間後もプレイすることが出来ます。皆さま、是非手に取って、遊んで見て下さい!

(まとめ)

さて、今回の産学連携プロジェクト。4月のオリエンテーションから始まり、中間企画発表、総合作品審査、受賞式、リリースと経て幕を閉じました。とても濃密な内容でした。優秀賞受賞チームの皆さんには、リリース準備の際に、+αの対応事を様々依頼しましたが、そのレスポンスの速さと的確な内容から、非常にスムーズに進めることが出来、感謝しております。

また、普段開発側の人間でない私にとっては、開発したゲームをリリースまで持っていくこと、そのために必要なもの、時間、やるべきこと、注意点、落とし穴、等々・・・通して体感することが出来たことはとても貴重な体験でした。こんな作業、手間をかけてゲームはリリースされお客様に届くのだと改めて認識したことと、ゲームを作り、世に生み出す開発者の方のお仕事を少しでも体験できたことも良かったです。

 

最後に・・・

このプロジェクトは、HAL学生さんの「ゲーム制作」や「チーム開発」への熱意、工夫、技術、拘り、愛、頑張りなしには成立しないプロジェクトです。あわせて、これらの企画~実施、運営までのサポートを下さったHALの先生方のお力添えやお気遣い・・・こちらも学びが多く、このような機会を頂けたことに感謝しています。関わって頂いた皆様、ありがとうございました。

 

(おまけ)

クレイジーヘッドボーイズ、どうしてもRANK Sがとれませんでした。28秒の分厚い壁、私はいつ越えられるのでしょうか。

 

私の中の最高記録のRANK Aで、「産学連携プロジェクト」(前編/後編)を締めたいと思います。(完)


mori

専門学校HAL×Aiming 産学連携プロジェクト(前編)


こんにちは。人事の森です。

今日は、学校法人・専門学校HALとAimingが産学連携の1つとして行った「産学連携プロジェクト」について紹介したいと思います。(前編)
「産学連携」とは、教育機関である学校法人・専門学校HALと、民間企業である株式会社Aimingが連携し、学生がスマートフォン用のゲーム開発に挑戦するというプロジェクトです。

このプロジェクトは、「今日は皆さんに、ちょっとゲームを作ってもらおうと思います」という映画バトルロワイヤル風に始まりました。(古いですか)

内容はこうです。

  1. Aimingが出したテーマに沿ってHALの学生がゲームを制作する
  2. 提出されたゲームを「企画段階」と「完成品」の2段階で審査する
  3. 優秀なゲームには、Aimingが用意した幾つかの賞を授与する

特に優秀なゲームは、Aiming名義で、App StoreとGoogle Playからリリースします。

 

制作は、企画期間1ヵ月/開発期間1ヵ月という、とても限られたスケジュールです。この内容に対し、HALの400名を超える学生が、チームを組んで挑戦してくれました。

Aimingがお題としたテーマは以下の3つです。

  1. 最初の3分のおもしろさ
  2. 新規性
  3. 遊びやすさ

この3つを軸に、作品審査を行いました。

iOSの開発は初めてという方が多い中、たくさんのチャレンジがあり、工夫があり、熱意があり、審査であるにも関わらず、ついつい楽しくプレイさせて頂きました。

企画段階のものから内容を大きく変更し、素晴らしくブラッシュアップされた作品もありました。ネットワークに挑戦し、オンライン要素を取入れた作品もありました。チームワークや頑張りの跡が見られる作品は、審査にも熱が入ります。

選びきることに苦悩はありましたが、Aimingが用意した賞は全部で4つ。
「優秀賞」、「ゲームデザイン賞」、「技術賞」、「審査員特別賞」です。

前編では、優秀賞を除く5つの受賞作品について紹介したいと思います。

 

 

まずは、ゲームデザイン賞:「Pechantet」(HAL大阪)

指でなぞった地面が切り取られ折り曲がり、そこに敵を挟んで倒すという、操作感と見た目も面白いタワーディフェンスです。ゲームデザインに優れているポイントは、リソース管理と操作が上手に融合している点です。大きくなぞると簡単に敵を挟めますが、次の敵を攻撃することが出来なくなってしまう。敵の動きを予想して、最小範囲で切り取り挟む。更に角度も考え遊ぶというテクニカルな要素がとても面白い作品です。

 

 

続いて、技術賞:「双璧のマジカライズ」(HAL名古屋)

画面いっぱいの大量のスライムを魔法の壁でプチプチ挟んで倒していく、小気味良く簡単な操作で楽しめるゲームです。
ゲームとしては荒削りであるものの、コアメカニクスである指でなぞったルートのスライムを巻き込んでいくというのが、”わかりやすいゲームデザイン + 面白いビジュアル + 簡単操作のユーザビリティ” として、バランス良くまとまっていました。
ベースとしてテクニカルなアプローチがあり、この美点を技術賞として評しました。

 

 

そして、審査員特別賞は個性豊かな3作品がノミネート。

「ヤンキーキャット」(HAL名古屋)

ヤンキーを操作して相手のヤンキーを倒す「喧嘩上等」のシミューレーションに、ネコの要素が加わることで癒やしの効果が得られるネコゲーです。
ベースは挟み将棋で、相手ヤンキーを挟んで倒していくというものです。そしてそこにネコ登場!
通常は倒すしかないヤンキーも、ネコを間に入れる(相手とネコを挟む)ことで場が和み、和解すれば相手を仲間にすることができます。
ネコ好きに悪い奴ぁいねぇ理論ですね。(私は犬派です。)
ヤンキーというクラシカルな題材ではあるものの、細かな動きや演出面など細部までこだわりが見え、ゲーム全体を通してクオリティの高さがうかがえるゲームです。
センスが光るテキストに、にやにやしながら審査しました。

 

 

「ぽより~」(HAL名古屋)

風船を思わせる妖精”ポヨリー”を、上手く操作し上昇させて故郷に帰してあげる、とても可愛いビジュアルのゲーム。
ポヨリーを指で挟んで空気を押し出し、その反動でどんどん上昇させてゴールに導いてあげます。
直感的な操作と、瞬時にルールを理解できるゲームデザインが秀逸です。
操作は簡単ですが、挟み方によってはポヨリーが右に左に飛んでいき、ゆっくり操作すれば落下していくので、慎重かつ大胆なプレイが求められます。
キュートな世界観も魅力のゲームです。

 

 

「日狭茶飯事」(HAL東京)

ふりそそぐ食品をトングで挟んで食べまくる。シンプルながら瞬間的に熱くなれるゲームです。
本能に訴えかける説明不要のゲームルールとポップなビジュアルが上手く組み合わさり、高い中毒性と、1人プレイながらも場を盛り上げることのできるパーティーゲームに仕上がっています。
ゲーム開始までのタイトルやイントロのカットシーンなどもポップな演出で彩られ、細部まで抜かりがありません。
丁寧な作りを感じます。プレイ動画は、YouTube投稿にも向いてるかもしれません。

 

さて、栄えある優秀賞は・・・!?(後編に続く)

 

(おまけ)HAL大阪での授賞式の1コマ

素晴らしいゲームを作ったチームメンバーの皆様と、素敵な先生で記念撮影★

 


syoshino

AssetBundleGraphTool を触ってみました


エンジニアの吉野です。

先日アップデートされたばかりの AssetBundleGraphTool v1.3 をこれまた先日リリースされた Unity 2017.1 に入れてみました。

AssetBundleGraphTool の bitbucket ページ
日本語マニュアル

今回はゲームで使用する Asset がどの AssetBundle に入っているかのテーブルデータをカスタムノードで作成したのでかいつまんで紹介しようと思います。

概要

ゲームで Asset を読むときに、開発中はローカルから、実機では AssetBundle を使いたいということが良くあります。
(Unite 2017 で紹介されていた Addressable Assets が入ればいらなくなるはずなので、それまでのつなぎで…)
これを満たすための仕様としては、おおむね以下の図のようになると思います。

asset load flow

この図の AssetBundleTable で使う AssetPath → AssetName 変換用のデータをカスタムノードで作ります。

完成したGraph図はこのようになります。

graph sample

カスタムノードの作り方は日本語のマニュアルの「カスタムノードを追加する」を見てください。
以下、作成したノードの要点を解説していこうと思います。

入力/出力するノードのタイプを指定する

今回は、「AssetBundle 名と AssetPath が設定されたノード」(Grouping)と 「AssetBundle をビルドするノード」(BundleBuilder)の間に入れたいので、以下のようにします。


    public override Model.NodeOutputSemantics NodeInputType
    {
        get
        {
            return Model.NodeOutputSemantics.AssetBundleConfigurations;
        }
    }

    public override Model.NodeOutputSemantics NodeOutputType
    {
        get
        {
            return Model.NodeOutputSemantics.AssetBundleConfigurations;
        }
    }

インスペクター上から AssetBundleTable を指定できるようにする

Inputされた情報を書き込む AssetBundleTable を渡せるようにします。
指定はエディタ拡張でおなじみの OnInspectorGUI(…) 部分に追加します。


public override void OnInspectorGUI(
    NodeGUI node,
    AssetReferenceStreamManager streamManager,
    NodeGUIEditor editor,
    Action onValueChanged)
{
...
    tableAsset = EditorGUILayout.ObjectField("AssetBundleTable Object", tableAsset, typeof(AssetBundleTable), false) as AssetBundleTable;
...
}

ビルド時に AssetBundleTable を更新する

Graph をビルドすると、カスタムノードの Build(…) が呼ばれます。この時に受け取った情報をTableに設定します。


public override void Build(
    BuildTarget target,
    Model.NodeData node,
    IEnumerable<PerformGraph.AssetGroups> incoming,
    IEnumerable<Model.ConnectionData> connectionsToOutput,
    PerformGraph.Output Output,
    Action<Model.NodeData, string, float> progressFunc)
{
...
    tableAsset.Clear();
    foreach (var ag in incoming)
     {
         foreach (var assetGroup in ag.assetGroups)
         {
             foreach (var inputAsset in assetGroup.Value)
             {
                 tableAsset.Add(new AssetBundleLoadPath(assetGroup.Key, inputAsset));
             }
         }
     }
     EditorUtility.SetDirty(tableAsset);
     AssetDatabase.SaveAssets();
...
}

AssetBundleTable 自身も AssetBundle にする

実機で使うので、AssetBundleTable も忘れずに AssetBundle にします。
幸いこの後に AssetBundle をビルドするノードがあるので、Output に追加して流します。


public override void Build(
    BuildTarget target,
    Model.NodeData node,
    IEnumerable<PerformGraph.AssetGroups> incoming,
    IEnumerable<Model.ConnectionData> connectionsToOutput,
    PerformGraph.Output Output,
    Action<Model.NodeData, string, float> progressFunc)
{
...
    EditorUtility.SetDirty(tableAsset);
    AssetDatabase.SaveAssets();

    if (Output != null)
    {
        var dst = (connectionsToOutput == null || !connectionsToOutput.Any()) ?
            null : connectionsToOutput.First();

        // 上流のノードから流れてきたものをそのまま渡します。
        foreach (var ag in incoming)
        {
            Output(dst, ag.assetGroups);
        }

        // AssetBundleTableを追加して渡します。
        var additionalOutput = new Dictionary<string, List<AssetReference>>();
        additionalOutput.Add(settings.tableAssetBundleName,
            new List<AssetReference> { 
                AssetReference.CreateReference(AssetDatabase.GetAssetPath(tableAsset), typeof(AssetBundleTableListData))
            }
        );
        Output(dst, additionalOutput);
    }
}

これで、作成した Graph がビルドされるたびに AssetBundleTable が更新されて、AssetBundle にまでなってくれます。
日本語のわかりやすいマニュアルがあるおかげで、すんなりと実装できてしまいました。

使ってみた感想

ノードの拡張機能があるおかげで Asset を読んで加工してなにかする、という機能をグラフィカルかつ低コストで作成できる素晴らしいツールだと思います。
カスタムノード以外にもいろいろな機能があるのでぜひマニュアルを見てみてください。
いろいろ応用できそうなので今後も活用していこうと思います!


Unity 2017.1.0 BetaでInspectorの入力ができなくなる問題を回避する方法


こんにちは。大阪スタジオ エンジニアの西村です。

現在開発中のプロジェクトではUnity 2017.1 Beta版を使用しています。

Unity 2017.1.0b3~Unity 2017.1.0f1のWindows版でInspectorの入力ができなくなるという不具合が発生していて作業に支障が出ていました。

人によっては不具合が発生しておらず、調査の結果Microsoft IMEを使っている場合のみ発生する事がわかりました。

回避方法

Unity使用時、キーボード設定をMicrosoft IME以外に設定する。

Google 日本語入力やUSキーボードを使用している人は不具合が発生していませんでした。

うっかり入力できなくなった時の対処方法

Componentメニューを開いて閉じるだけでInspectorに入力できる状態に戻ります。

不具合はUnityに報告済みで、いずれ修正されるでしょう。


mewlist

uGUI 描画優先度のチートシート


皆様,こんにちは!
株式会社Aiming の 土井と申します!
リードソフトウェアエンジニアをやっております!

ここ数年は,業務で Unity の uGUI を使って UI 開発をする機会が多いのですが、
Order in Layer, Sorting Layer, ヒエラルキ上の並び順……(つд⊂)ゴシゴシ
Unity では重なり順を指定する項目が多いですよね。
これらの項目間の優先度が実際にどうなっているのか理解していなかったため、調査を兼ねてチートシートを作ってみました!

描画優先度を指定するものを列挙してみた

どうやらこれらの関係を全て調べ上げれば良さそうです。

チートシート

調べました。
画像は実際に Unity の GameView で表示されたもののキャプチャです。

これで、もう UI の重なり順で悩まない!

解説

カメラ毎の優先度

  • Canvas に設定された Camera による優先度
    • ScreenSpace: Overlay 設定のものが最優先
    • 次いで Depth 値が高いものが優先

同じカメラに設定されたキャンバス同士

  • SortingLayer が高い Canvas が優先
    • 同じ SortingLayer 同士では、 Order In Layer の値が高い Canvas が優先
      • さらに同じ Order In Layer 同士では、Z 値が低い(カメラに近い) Canvas が優先

Mesh や パーティクルなど UI 以外の Renderer について

  • SortingLayer や Order In Layer の値による重なり順の制御ができる
  • ただし、SortingLayer と Order In Layer が同じ値を持つ Canvas がある場合、ヒエラルキ上の並び順による重なり順のソートは行われないので、 固有の Order In Layer 値を設定しよう

Render Queue について

  • UI の描画は、 RenderQueue = “Transparent” にて行われるため、独自のマテリアルを使用する場合は RenderQueue の値に 2501 以上を指定する必要がある

最後に

  • UI のレイヤーの間に 3D モデルを表示したりエフェクトを出したりといった要件のときには、まず全体の UI のレイヤー構成を整理して仕様化しましょう。行き当たりばったりで重なり順をいじっていると混迷を極めます
  • MeshRenderer などは標準でインスペクタ上から SortingLayer や Order In Layer が設定できません。
    • https://docs.unity3d.com/ja/current/ScriptReference/Renderer.html
    • 自前でスクリプトから設定する必要があります
      • (Order In Layer は sortingOrder というプロパティです)

おしまい。


Unity5.6.0で追加されたTest RunnerのPlayModeを使ってみた


こんにちは。大阪スタジオ エンジニアの西村です。

Unity 5.6.0からTest RunnerにPlayModeが追加されました。以前からあったEditModeのテストではカバーできなかったフレームをまたぐ非同期処理などのテストが可能になります。ざっくり試してみた結果をまとめてみました。この記事ではUnity 5.6.0f3を使用しています。

PlayModeを有効にする

初期状態ではPlayModeが無効になっているので有効にします。まずWindow – Test RunnerでTest Runnerウィンドウを開きます。

PlayModeタブを選択すると”Enable playmode tests”というボタンがあり、これを押した後でUnityを再起動する必要があります。

これでPlayModeが使えるようになりました。

PlayModeでテストを実行してみる

Create Playmode test with methodsを押すとテンプレートスクリプトが作成されます。

NewPlayModeTest.cs

using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;

public class NewPlayModeTest {

    [Test]
    public void NewPlayModeTestSimplePasses() {
        // Use the Assert class to test conditions.
    }

    // A UnityTest behaves like a coroutine in PlayMode
    // and allows you to yield null to skip a frame in EditMode
    [UnityTest]
    public IEnumerator NewPlayModeTestWithEnumeratorPasses() {
        // Use the Assert class to test conditions.
        // yield to skip a frame
        yield return null;
    }
}

スクリプトがコンパイルされるとPlayModeにテストが追加されます。

とりあえず手を加えずにRun Allしてみると。シーンがテスト用のものに入れ替わりUnityがPlay状態になります。しばらく待つとテストが実行され結果がTest Runnerウィンドウに反映されます。

当然なにもないので成功です。

次は失敗させてみましょう。適当にAssertを追加します。EditModeのテストと同じ感覚で書くことができます。

NewPlayModeTest.cs

using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;

public class NewPlayModeTest {

    [Test]
    public void NewPlayModeTestSimplePasses() {
        // Use the Assert class to test conditions.
        Assert.IsTrue(false, "失敗させてみる");
    }

    // A UnityTest behaves like a coroutine in PlayMode
    // and allows you to yield null to skip a frame in EditMode
    [UnityTest]
    public IEnumerator NewPlayModeTestWithEnumeratorPasses() {
        // Use the Assert class to test conditions.
        // yield to skip a frame
        Assert.IsTrue(false, "失敗させてみる");
        yield return null;
    }
}

はい、失敗しました。

PlayModeらしいテスト

ここまではEditModeでも実行できる内容です。次にEditModeでは出来なかったフレームの更新がある状態になっているか試してみます。

NewPlayModeTest.cs

using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;

public class NewPlayModeTest {

    [Test]
    public void NewPlayModeTestSimplePasses() {
        // Use the Assert class to test conditions.
    }

    // A UnityTest behaves like a coroutine in PlayMode
    // and allows you to yield null to skip a frame in EditMode
    [UnityTest]
    public IEnumerator NewPlayModeTestWithEnumeratorPasses() {
        // Use the Assert class to test conditions.
        // yield to skip a frame
        yield return null;
    }

    [UnityTest]
    public IEnumerator 複数フレームに渡ってテストできる() {
        // Time.timeは同一フレーム中は同じ値を返す
        var startTime = Time.time;
        System.Threading.Thread.Sleep(1000);
        Assert.AreEqual(startTime, Time.time);

        yield return new WaitForSeconds(1f);
 
        // フレームが変わっていればTime.timeの値が変わっているはず
        Assert.AreNotEqual(startTime, Time.time);
        yield return null;
    }
}

複数フレームに渡ってテストできることがわかります。

MonoBehaviourTest

MonoBehaviourTestと言うものがありますが詳しい使い方がわかりませんでした。動作テストに使用したコードは以下の通り。

ExampleBehaviour.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ExampleBehaviour : MonoBehaviour {
    protected int counter = 0;

    // Use this for initialization
    void Start () {
 
    }
 
    // Update is called once per frame
    protected void Update () {
        counter++;
    }
}

ExampleBehaviourTest.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.TestTools;

public class ExampleBehaviourTest : ExampleBehaviour, IMonoBehaviourTest {
    public bool IsTestFinished { get; private set; }

    // Update is called once per frame
    new void Update () {
        base.Update();
        Debug.Log(counter);
        if (counter > 10)
        {
            // ここで止めておかないと他のテストの裏でも動き続ける
            gameObject.SetActive(false);
            IsTestFinished = true;
        }
    }
}

NewPlayModeTest.cs

using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;

public class NewPlayModeTest {

    [Test]
    public void NewPlayModeTestSimplePasses() {
        // Use the Assert class to test conditions.
    }

    // A UnityTest behaves like a coroutine in PlayMode
    // and allows you to yield null to skip a frame in EditMode
    [UnityTest]
    public IEnumerator NewPlayModeTestWithEnumeratorPasses() {
        // Use the Assert class to test conditions.
        // yield to skip a frame
        yield return null;
    }

    [UnityTest]
    public IEnumerator 複数フレームに渡ってテストできる() {
        // Time.timeは同一フレーム中は同じ値を返す
        var startTime = Time.time;
        System.Threading.Thread.Sleep(1000);
        Assert.AreEqual(startTime, Time.time);

        yield return new WaitForSeconds(1f);
 
        // フレームが変わっていればTime.timeの値が変わっているはず
        Assert.AreNotEqual(startTime, Time.time);
        yield return null;
    }

    [UnityTest]
    public IEnumerator MonoBehaviourのテスト() {
        yield return new MonoBehaviourTest<ExampleBehaviourTest>();
    }
}

MonoBehaviourTestを利用してMonoBehaviourを実行することも可能です。IMonoBehaviourTestを実装したMonoBehaviourがIsTestFinishedがtrueを返すことでテストが完了します。IsTestFinishedがfalseのまま30秒経過するとタイムアウトしますが、タイムアウトしても完了として扱われてしまいます。

MonoBehaviourTest実行中にAssertを呼び出してしまうと以後のテストが失敗してしまうため、Assertを呼び出すことでテスト単体を失敗させる事ができません。MonoBehaviourTestについてはそもそも使い方を間違えている可能性もあるので深追いしないことにしました。

Playerでテスト

左上のRun AllではUnity Editor上のPlayモードで実行されますが実際のPlayer上でも実行することが出来ます。

Build SettingsのSwitch PlatformでAndroidに切り替えてみると、右上のボタンがRun all in player(Android)に変わります。

実行してみるとビルドが走りAndroid端末でテストが実行されます。実行結果がUnity上のTestRunnerにフィードバックされないのは残念ですが手軽に実行することが出来ます。

まとめ

今回調べた中で分からなかった事

  1. UnityEngine.TestTools.MonoBehaviourTestの扱い方
  2. コマンドラインからPlayModeのテストを実行する方法

MonoBehaviourTestの扱い方が分からなかったため不完全燃焼ではありますが、PlayModeを利用することで今まで出来なかった非同期処理のテストも書くことが出来るようになりました。また、コマンドラインからの実行が出来ないのでCIに組み込む事が出来ませんが、コードレビュー時など手元でサクッと実行できるのは便利です。

今後もPlayModeテストをCIに組み込むことを視野に入れてウォッチを続けていきます。


Unity3DのDIフレームワーク、Zenjectの紹介


はじめまして。エンジニアの石井と申します。

今回は現在担当プロジェクトで使用しているUnity(ゲームエンジン)用DIフレームワーク、Zenjectを紹介させていただきます。

Zenjectとは

https://github.com/modesttree/Zenject

ZenjectはUnity3D向けに作成された、DI(依存性の注入)フレームワークです。
Zenjectを使うことでオブジェクト間の依存関係を外部から解決することができます。
簡単になにが良いかを説明しますと、
依存オブジェクトを別の入れ物(コンテナ)に格納しておきコンテナ経由で使うことで、
コンストラクタやメソッドの引数で渡していたり、自身でnewしていたり、FindObjectしていた部分をなくすことができます。

Zenjectサンプル

Zenjectを使ってのUIイベント処理の簡単なサンプルを作っていきます。
今回はボタンが押された時のイベントを処理するサンプルです。

1.インストール

AssetStoreからか、
https://github.com/modesttree/Zenject/releases
からダウンロードしてUnityのプロジェクトにインポートしてください。

2.Contextの作成

シーン上にContextを作成します。
右クリックからScene Contextを選んでください。
Zenject_context

3.Installerの作成

コンテナへの格納(Bind)にZenjectはInstallerというスクリプトを使用します。
今回はSingletonとしてオブジェクトをBindしていきます。

シーン上にGameObjectを作成して、
下記スクリプトをAdd Componentしてください。
※直接SceneContextでも問題ありません。
Zenject_Installer

using System;
using Zenject;

public class InstallerSample : MonoInstaller<InstallerSample>
{
    public override void InstallBindings()
    {
        Container.Bind<ZenjectSample>().AsSingle();
        Container.Bind<IInitializable>().To<ZenjectSample>().AsSingle();
        Container.Bind<IDisposable>().To<ZenjectSample>().AsSingle();
    }
}

4.ContextにInstallerをアタッチ

ContextにInstallerをアタッチすることでInstallerが機能します。
SceneContextのInstallersに、作成したInstallerSampleをアタッチしてください。

Zenject_Context_Installer0

5.UIの作成

UIを作成していきます。
下記のようにボタンを2つ作成し、
Zenject_UI_hierarchyZenject_UI

それぞれ下記のようにスクリプトをAdd Componentします。
Zenject Bindingスクリプトにより、Installerに定義しなくてもBindすることができます。
Identifierを使うことで、個別にInjectすることもできます。

Zenject_UI_Parts

using UnityEngine;
using UnityEngine.UI;
using UniRx;

public class UIView : MonoBehaviour
{
    [SerializeField]
    Button button;

    [SerializeField]
    Text text;

    public IObservable<string> OnClickObservable()
    {
        return button.OnClickAsObservable().Select(_ => text.text);
    }
}

イベントの変換はUniRxを使い、Textをstringで送出します。

6.サンプルクラスの作成

サンプルクラスを作成します。
[Inject]アトリビュートにより先ほど作成したUIViewが注入されます。
IInitializable.Initializeメソッドにより初期化され、
各ボタンのClickイベント購読し、押されたらOnClickメソッドが呼ばれるようになっています。
Sceneの切り替えやゲームの終了などでContextが破棄されるタイミングでIDisposable.Disposeメソッドが呼ばれ、
購読を停止しています。

using System;
using System.Collections.Generic;
using UniRx;
using Zenject;

public class ZenjectSample : IInitializable, IDisposable
{
    [Inject]
    List<UIView> buttons;

    List<IDisposable> subscriptions = new List<IDisposable>();

    void IInitializable.Initialize()
    {
        UnityEngine.Debug.Log("Initialize");

        buttons.ForEach(button =>
        {
            subscriptions.Add(button.OnClickObservable().Subscribe(text => OnClick(text)));
        });
    }

    void OnClick(string buttonText)
    {
        UnityEngine.Debug.Log(buttonText);
    }

    public void Dispose()
    {
        subscriptions.ForEach(subscription => subscription.Dispose());
        subscriptions.Clear();

        UnityEngine.Debug.Log("Dispose");
    }
}

7.動作確認

Sceneが読み込まれる際に、Initializeメソッドが呼ばれ、
ボタンが押されるたびにボタンのTextがログに表示され、
最後にDisposeが呼ばれていることがわかります。

Zenject_log

おわりに

簡単に紹介させていただきましたが、
他にもZenjectには様々なContext、Installerが用意されていますので、
依存関係の解決でお困りの方はぜひ一度試してみてください。