うどんゲームメモ

ゲームの技術メモをまったりと

エンジニアインターン体験記(ITベンチャー多め)

この記事はNITMic Advent Calendar 20日目の記事になります
お前何回書くんだよみたいな感じですが、自分の担当する最後の記事なので温かい目で見てください
去年何社かお邪魔させてもらった短期のインターンについて話していきたいと思います
エンジニアを目指す方や、インターン行こうか迷ってる方にとって少しでも参考になれば幸いです


会社ごとの感想

自分は短期インターンとして伺った会社は4社です、この4社ごとの簡単な内容の説明と学んだことなどを書いていきます

1.サイバーエージェント

1社目はITベンチャー大手であるサイバーエージェントさんです
サイバーエージェントさんについては2回短期インターンにお邪魔させてもらいました
1つ目はTechnical Creator Challengeというインターンです
内容としては5日間の短期開発インターンで、テレビアプリの開発をしました
中でも特徴的なのは企画、デザイン、実装までを全て一人でやるということで、デザインからエンジニアリングまで様々な技術を持つ学生が集まる非常に勉強することが多いインターンでした
自分が参加したのが栄えある第一回で、最終審査には社長である藤田晋さんがいらっしゃったのも印象に残っています
同じインターンに参加した学生が紹介インタビューを受けているので良ければ参考にしてみてください

developers.cyberagent.co.jp

2つ目は京都ハックというインターンです
内容としてはこちらも5日間の短期開発インターンです、京都という地域に結び付けたサービスの開発をしました
こちらはチーム開発で1チーム3人程度で作成をしました、Webアプリやスマホ用アプリからドローンを応用したアプリまで様々でした(自分はARのサービスを作りました)
実際に京都の町に繰り出しながら開発案を練ったりなど、普段の個人開発では学べないようなことも多くいい機会になりました

2.エイチーム

2社目は地元名古屋で活躍するエイチームさんです
エイチームさんではWebサービスとゲーム開発の2つの1dayインターンを実施しており、自分はゲーム開発インターンに参加させていただきました
内容としては1日のUnityを用いたゲーム開発で、最終的に工夫をコンペ形式で競うものでした(チーム開発ではなく個人開発)
地元開催ということもあり、自分の学校やゲーム開発で交流のある専門学校の生徒が多く、とても和気あいあいとしたインターンでした(東京と大阪でも開催されます)
コンペ上位者には1か月のコンテスト型インターンへの参加が認められ、そこからさらにチーム開発を行うことになります

3.カプコン

3社目はコンシューマーゲームでおなじみのカプコンさんです
開催場所は大阪のカプコン本社近くにある研究開発ビルで、関西圏から多くの学生が参加していました
内容としては2日間に渡るチームでのゲーム開発コンペでした、俗にいうゲームジャムですね
審査をする方々も有名なゲームに携わっているクリエイターの方々ばかりで、フィードバックを直にいただけるだけでもいい経験になりました
足りないところをしっかりと指摘していただけるため、自分の強いところや弱いところがはっきりしていい機会になりました

4.アカツキ

最後の紹介になるのは成長に勢いのあるアカツキさんです
内容としては1日のゲームジャムだったのですが、それだけのために2泊分のホテルと交通費を出していただけたのはびっくりしました
VRのゲームを1日で開発することになり、結構ぎりぎりのスケジュールの戦いでしたが学ぶものも多かったです
開発の前に参加者全体でアイデアソンのようなものも行われ、ゲームの企画を考えるいい機会にもなりました
結果的にチームにも恵まれ、優勝できたので個人的には印象深いインターンですね
VRのゲームを作成し、それを実際に会社で開発しているような人にプレイしていただきフィードバックをいただけたのもかなり貴重な体験でした


短期インターンを経験して

短期インターンを通して得たものですが、まず確実なのは開発力ですね
短期インターンは短期という性質上ハッカソン形式をとるものが多く、いかに少ない時間で機能を実装していくかの訓練になります
また色々な技術者との交流や共同開発も行うため、多様な角度からの実装アプローチが身に付きます
それに連ねて、ギークな人脈も増えていきました
学生vs学生といった形式が多いため参加するたびにこんな学生もいるのかという発見ができます、インターンを機に一緒に開発をする仲間が増えアウトプット形式の幅が広がりました
また審査は会社で実際に開発を行っているような方々がされるため、会社について話を伺う事も出来ます
ですが、会社でどのような雰囲気で開発がされていて技術選定はどうなっているかを見定めたい場合は長期インターンの方が多くのことを知れて適しているかと思います


インターンを受けるには

インターンを受けたい!という学生さんの技術力にもよりますが、インターンは全部が全部行きたいところに行けるわけではないです
所によっては倍率が100倍などのインターンもあり、正直落ちることも多々あります
自分の行きたいインターンをしっかりと見定めて、自分の技術をしっかりとアピールすることが重要になってきます
特にエンジニアインターンだと何かしら見せることのできる成果物やソースコードがあると良いですね
インターンは学生の内しか行けない貴重な機会なので是非トライしてみてほしいです

Blenderでゲームのコストカットしたりタイトル画面作ったりしてみた

この記事はNITMic Advent Calendar 18日目の記事になります
今回はBlenderを用いたちょっとしたテクニックを紹介します
Blenderの自体の操作説明に関しましては省略しますので、ご了承ください


ゲームとレンダリングコスト

最近ではハイエンドなグラフィックを売りにしたゲームが増えてきました
中でも本当にこれはCGなのか?と疑ってしまうようなものもあります
しかし、ハイエンドなグラフィックほど裏では莫大な計算処理が施されています
リアルタイムレンダリングでそういったリッチな表現をこなし続けるというのは、不可能ではありませんがそれ相応のグラフィック性能を要求されることになります
特に流体シミュレーションや、サブサーフェス・スキャタリング、透過処理といった重めの処理はリアルタイムレンダリングだとそれっぽい表現でぼかすということも少なくありません
でもリッチな表現を使いたい!という人のために、今回はBlenderを使ってその表現をプリレンダリングし、テクスチャに起こしてしまうことで比較的低コストでリアルな表現を取る方法を紹介します

Blenderでプリレンダリング

リアルタイムに計算するのが難しいならあらかじめ計算してしまえ!ということでBlenderを使ったプリレンダリング技法の紹介をしていきます
今回使用するのはBlenderに標準で搭載されているCyclesレンダーというレンダリングエンジンです
後、今回レンダリングをより快適に行うためGPUレンダリングを採用しています、Blenderはこういう切り替えもお手軽にできるのでお勧めです
f:id:myudon:20171217222351p:plain
今回題材にするのはこの何の変哲もない宝石の入った宝箱です、これにCyclesレンダーを用いてまずそれっぽいリッチな加工をしていきます
今回はBlenderを使ってリッチな表現をするという趣旨ではないため、そこの過程については省略します
f:id:myudon:20171217222716p:plain
分かりやすくコテコテに表現を盛ってみました
金属光沢やIBL(Image Based Lighting)、透明処理や屈折光など重い処理が盛り盛りです
f:id:myudon:20171217224445p:plain
このレンダリング結果をテクスチャに焼いていきます、右下のメニューにBakeという項目が存在するので、そこで焼く表現の設定や実際に焼くコマンドを行います
また、この時Samplingの項目を設定してあげることで精密度を上げることができます、もちろん細かいほうが綺麗ですがその分レンダリングにも時間がかかるのでそこは注意です
(あまりにも設定を上げ過ぎるとBakeに数時間かかっちゃったりします)
また、Bake先のテクスチャについてはマテリアル内で何にもつながってないテクスチャが必要となります、ここ割とつまづきやすいので注意しましょう
f:id:myudon:20171217235158p:plain
またBakeするからには、UV展開がされていることも必須なのでその辺の手順もしっかりと踏みましょう
f:id:myudon:20171217230824p:plainf:id:myudon:20171217230827p:plain
宝箱の外部のテクスチャを結果の例として焼いてみました
映り込みまでもがしっかりとテクスチャに反映されているのがわかると思います、リアルタイムで計算せずにテクスチャにあらかじめレンダリング結果を焼くことでリッチな表現を残しつつコストカットができるというわけです
勿論、リアルタイムレンダリングとは違って、動かしたり違う視点から見た際に違和感が出てしまうというデメリットがあります
なので使いどころをしっかりと見極めて、使えそうなところはコストカットを図っていくといいでしょう

プチ応用例(タイトル画面の作成)

一般的には上記のような3Dモデルのレンダリングコスト削減に用いる技術ですが、使い方によってはこんなこともできちゃいますという例です
f:id:myudon:20171217231952p:plain
これは自分が過去に制作したゲームのタイトル画面です
個人制作であったため、タイトル画面などのデザインリソースが間に合わずどうしようか画策していた時にある方法を思いつきました
それは、Blender内でタイトル用の1シーンを作り、テクスチャとして焼いてしまおうという方法です
f:id:myudon:20171217233025p:plain
制作風景です、カメラの前にゲーム内で使用するキャラクターやオブジェクトを配置していきます
タイトル用なので解像度あげあげでリッチに仕上げていきます、それでも焼くのにかかった時間はせいぜい1時間ほどでした
f:id:myudon:20171217233322p:plain
これがオブジェクトの配置が終わり、環境光も含めてベイクしたものです
3Dモデルを配置していくだけなので、どんな構図でも大丈夫なわけです
後はこの作業が撮影監督になった気分で楽しいですね!
f:id:myudon:20171217233849p:plain
後はこの画像を元にPhotoShop等のデザインツールで仕上げを行います(自分はGIMPでやりました)
ここにタイトルロゴなどを加えて完成となりました、制作期間もそんなにかからなかったです
このように、ちょっとしたワンシーンを画像にしたい時などにもBlenderは活用できるので試してみてはいかがでしょうか

Unity開発で使うライブラリ(アセット)備忘録

この記事はNitmic Advent Calendar 13日目の記事になります
いい加減UnityじゃなくてCGの話しようと思ったんですけどとりあえずそれは来週にでも回そうかと・・・
今回は自分がゲーム開発する際によく使うライブラリだったりアセットだったりをまとめようかなと思い、書きました
早い話が前回のデバイス紹介のライブラリ編です
またお前かよみたいな感じですけどお暇な人は読んでみてください


1.UniRx

1つ目は自分のもっとも使っているライブラリ、UniRxです
Rx(Reactive Extensions)というのは所謂リアクティブプログラミングをObserverパターンを用いて実現させるためのライブラリを指します
それをUnity向けに作ったのがUniRxというわけです
イベントストリームという、イベントを時系列の流れとして捉える処理が特徴的であり、非同期処理などに長けています
ゲームで言えば何秒後かに処理するといったタイマー処理だったり、一連の動作が行われたかどうかを待機する処理などが書きやすいですね


2.Vuforia

2つ目はARライブラリ、Vuforiaです
主に短期インターンハッカソンでお世話になりました、簡単なARコンテンツを作る際に重宝しています
マーカーベースのARコンテンツを作る際に、ほとんどの工程を担ってくれます(マーカーベースというのは任意の画像をかざすことでコンテンツを提供するもののことです)
画像をかざして3Dモデルを出すという基本工程ならばコーディングが要らないほどに簡単なので試してみてはいかがでしょうか


3.SocialWorker

3つ目はSNS連携を行うSocialWorkerです
Unityといえばアプリ開発であり、アプリといえばSNS連携が欠かせなくなってきています
SocialWorkerは特に難しい記述も必要なく、アプリ内でのSNS投稿がサクッと出来ちゃいます
サポートしているのはiOS/AndroidでのTwitterFacebook、Line、Instagram、メールです
もちろん連携してデータを色々と使ったりなど柔軟なことをする場合には自分でAPIを叩いてやるべきだと思いますので、簡易的な投稿機能などがほしいときに使ってみるといいでしょう


4.DOTween

4つ目はアニメーションライブラリ、DOTweenです
イラストが変化しつつ遷移していくようなアニメーションのことを一般的にTweenアニメーションと呼びます(フェードしてきたり、拡大縮小したりなど)
そのTweenアニメーションをUnityで実現するためのライブラリで、自分がTweenアニメーションを実装する際に一番使うものです
特徴的なのがアニメーションをシーケンスという連続した流れで捉えることができることですね
複数のアニメーションを動的に結合したり、同時に処理したりなど、多様な使い方をすることができます
初心者の方でも扱いやすく、表現の幅がぐんと広がるのでおすすめです


5.Julius

5つ目は音声認識ライブラリ、Juliusです
その名の通り、音声を認識してそれを文字列に起こしたりすることができます
単純な音声認識なら割とすぐ出来てしまうので、ちょっとしたアプリを作るときに役立ちます
ただ、会話などをするには精度など様々な点で難しいところがあるので、ピンポイントなワード認識用って感じです


6.Zenject

6つ目はDIフレームワークであるZenjectです
自分が秋ごろに書いた記事でも説明した、Unityの設計においてDIコンテナを採用する際に用いるものです(詳しい説明はその記事を読んでいただければ!)
Unityでシングルトンを用いて設計を行うと割と密結合になってしまったり、肥大化したシステムでサイクルがとっ散らかったりしまったりして自分はあまり好きではないです
Zenjectを用いて必要なパーツを提供する機構を導入してあげるとそういった点がかなりスッキリするので自分は積極的に使いたいなと思っています


7.NGUI

7つ目はUIライブラリであるnGUIです
Unityには標準でuGUIというUIを実装するためのサポートシステムが存在しますが、それよりもより自由度と難易度を上げたのがnGUIになります
少し癖が強いですが、3D空間上のUIやテキストと画像混合のアニメーションなど、使いこなすと広い表現が可能になります
ただnGUIでしか出来ないということが割と限られていたり、uGUIと処理の細部が違っていたり(イベント処理がraycastじゃなくてcolliderだったり)するので積極的な採用をするよりは使いどころを見極めるべきものだと思います


いかがでしたでしょうか、所謂コンテンツの表現を伸ばすものと、そもそものコーディングをアシストするものを紹介しました
後者に関しては、ライブラリ一つで構造がすっきりするというのは割とよくある話なのでまずは試してみてはいかがでしょう
導入しただけで開発期間が大きく短縮されるのはよいことですし、あるものはどんどん活用していきましょう(勿論それなりの理解をした上でですが)
また機会があればこれらのライブラリの活用例であったり簡単な解説を記事にしようかなと思います

Unityで強化学習しよう! ML - Agentsのススメ

始めに

本記事はサムザップ Advent Calendar 2017 10日目の記事になります
昨日の記事は@xxxxxxxxxxさんのLua+PEGでiniをparseするでした!


今年の9月にUnity公式から強化学習ライブラリが公開されました blogs.unity3d.com

公開したてでまだ若干使い勝手の悪い部分もありますが、TensorflowSharpなどで自力で強化学習環境を構築するよりは断然楽だと思います
今回はこちらのライブラリの紹介と、それを使うために構造の解説をしていきます
環境導入であったり実際にどう学習させるかは、いくつかのサイトがサンプルを用いて説明されているので、そちらを参考にしていただければ幸いです(自分が参考にしたサイトはこちら)

Unityの公式サンプルml-agentsでAIを試す - tanaka's Programming Memo

ML-Agentsとは

先程も書きましたが、ML-AgentsはUnity内で強化学習をするためのライブラリです
Googleが公開している機械学習用ライブラリ「Tensorflow」、OpenAIが2017年に発表した強化学習アルゴリズム「PPO(Proximal Policy Optimization)」、これら2つがこのライブラリのベースとなっています
python等をこちらが組む必要はなく、普段のUnity開発の要領で学習環境などを組み上げれば強化学習が行える優れものです


ML-Agentsの構造

MLAgentsの構成は主に3種類のパートに分かれます
f:id:myudon:20171208155603p:plain
Unityのシーン内にこれら3パートを配置することで強化学習を行うことができます(BrainはAcademyの子にする)
Agent、Brain、Academy、この3パートをソースコードを交えつつ解説していきたいと思います

Agent

まず学習するのに必要な状態、行動、ルールの定義を行うパートです
例としてスーパーマリオで考えてみたいと思います
最初に状態を考えてみましょう、マリオの位置や敵の位置、キノコを所持しているか等がありますね
次に行動です、歩く、ジャンプする、状態によってはファイアボールで攻撃するなどが挙げられます
最後にルールを考えます、マリオは敵に当たってはいけないため敵に当たったときには負の報酬を、前に進めば進むほどゴールに近づいていくため正の報酬を与えてあげます
実際はこんなに単純ではないですがこのようにして学習のために機械が考えることを定義してやるのがAgentパートです

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

//簡易的なサンプル
public class AgentBase : Agent
{
    [SerializeField]
    private Transform _mario;

    /// <summary>
    /// エージェントの初期化処理です
    /// 必須ではなく、Agentを立ち上げた際に1回だけ呼ばれます
    /// </summary>
    public override void InitializeAgent()
    {

    }

    /// <summary>
    /// 状態の取得です
    /// ここで状態を定義するため、学習において必須になります
    /// Transformやコンポーネントの状態、他のオブジェクトの情報など、学習の判定に際して必要な情報を定義づけします
    /// 状態はfloat配列で渡すため、情報をfloat化してあげる必要があります
    /// </summary>
    /// <returns>エージェントの状態</returns>
    public override List<float> CollectState()
    {
        List<float> state = new List<float>();
        state.Add(_mario.position.x);
        state.Add(_mario.position.y);
        state.Add(_mario.position.z);
        return state;
    }

    /// <summary>
    /// 1ステップごとにエージェントが行う動作の定義づけです
    /// 動作を示すパラメータはfloat配列によって渡されるためそれを元に何をするかを決定していきます
    /// actionの動作タイプにもケースに分けて既定の動作をするタイプと、物理挙動など小数単位で動作が分類されるものとあるので作るものに沿って考えていく必要があります
    /// また、ここで報酬の定義を行い、その報酬によってリセットなどの処理も行います
    /// </summary>
    /// <param name="action"></param>
    public override void AgentStep(float[] action)
    {
        if (action[0] == 0)
        {
            _mario.position += new Vector3(0.5f, 0f, 0f);
        }
        else if (action[0] == 1)
        {
            _mario.position += new Vector3(-0.5f, 0f, 0f);
        }

        //敵に当たったら報酬をマイナスして、学習をリセットしてみる
        Collider[] hitObjects = Physics.OverlapBox(_mario.position, new Vector3(0.3f, 0.3f, 0.3f));
        if (hitObjects.Where(col => col.gameObject.tag == "enemy").ToArray().Length == 1)
        {
            reward = -1f;
            done = true;
        }
    }

    /// <summary>
    /// 1エピソード分の学習が終わった際にリセットしない場合に呼ばれるメソッドです
    /// 1エピソードの学習終了時に基本はリセット処理を呼びますが、設定で呼ばないようにしている場合こちらの処理を通すことができます(インスペクタで設定できます)
    /// リセット処理を行うとエピソード終了フラグもリセットされますが、こちらは残ったままになります(シーンからAgentを取り除くときなどに使用するとか)
    /// </summary>
    public override void AgentOnDone()
    {

    }

    /// <summary>
    /// Agentのリセット処理です
    /// 1エピソード分の学習が終わった後にAgentを最初の状態に戻します
    /// </summary>
    public override void AgentReset()
    {
        _mario.position = new Vector3();
    }

}

最低限状態の定義であるCollectStateと行動やルール定義を行うAgentStepさえ記述がされていればAgentは機能を果たすことができます
サンプルコードでは記述がされていませんが、正の報酬がないと基本的にはAgentはモチベーションを持って行動することができません
なのでしっかりと報酬を定義し、自分の望んだルールを正確に実装することが強化学習において大切になってきます

Brain

Brainはその名の通り行動を考える部分になります、Agentに行動を指示し制御します
Brainの行動決定には4つのタイプがあります(タイプ自体はインスペクタからいじることができます)
1つ目がExternalです、外部からの制御、いわばTensorflowから制御させるタイプです
2つ目がInternalです、強化学習によって得られた学習データによって制御させるタイプです
3つ目がPlayerです、単純にプレイヤーがコントローラーなどから制御させるタイプです
4つ目がHeuristicです、コーディングによって制御させるタイプです
以上の4タイプを用いてBrainからAgentに行動を指示していきます、基本的にはPlayerやHeuristicで環境の確認を行い、Externalで学習、Internalで学習結果の利用を行っていく流れですね
Brainに関しては特にソースを記述する必要はなく、インスペクタ上の設定で基本的には十分です

Academy

学習における環境を定義する部分です、学習ステップのスピードやエピソード単位での学習量の調整、また学習時のプレビュー設定も可能です
また、ステップごとの環境の処理やエピソードごとに環境をリセットする場合にも処理をします

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

//簡易的なサンプル
public class MarioAcademy : Academy
{

    [SerializeField]
    private GameObject _mario;

    /// <summary>
    /// Academyの初期化処理です
    /// 環境を立ち上げた際に1回だけ呼ばれます
    /// </summary>
    public override void InitializeAcademy()
    {

    }

    /// <summary>
    /// 1ステップ毎に環境側が行う動作です
    /// 動的にオブジェクトを制御したり、resetParameterを使って環境状態の制御を行ったりします
    /// </summary>
    public override void AcademyStep()
    {

    }

    /// <summary>
    /// Academyのリセット処理です
    /// 1エピソード分の学習が終わった後にAcademyを最初の状態に戻します
    /// 今回は分かりやすくFindで記述しました
    /// </summary>
    public override void AcademyReset()
    {
        //敵をリセットしたり
        var enemys = GameObject.FindGameObjectsWithTag("enemy");
        foreach(GameObject enemy in enemys)
        {
            Destroy(enemy);
        }

        //ステージ情報のリセットなどもここで行うと良いでしょう
    }

}

Academyに関しては記述の必要がないときは何も書かなくても大丈夫です
上記のサンプルコードはかなり簡易的ですが、学習環境が複雑化してくるとなかなかに大変になると思います


まとめ

今回はML-Agentsで実際に強化学習をするためにUnity側が何をすればいいかを解説しました
実際は強化学習の用途などによって必要な実装部など大きく変わってくるため、その都度公式のドキュメントを参考にし実装をしていくことになります
Unityで強化学習が使えるようになることはゲーム開発のみならず、学術的な研究にも応用できるため知っておいて損はないかなと思います
今現在自分もこのML-Agentsを使って自律型AIや自動テスト機構などを開発する試みをしています、成果が出次第、また投稿します
少しでも強化学習に興味が湧いた人は、簡単なサンプルもありますので触ってみてはいかがでしょうか

Unityと愉快なデバイス達

自分が昨年まで所属していた部活NITMicが今年はAdvent Calendarをやります!

adventar.org

この後も何回か書く予定ですが、とりあえず6日目を担当します
今回はUnityの開発において、どのようなデバイスを使って開発ができるかを紹介していきます
有名なデバイスから、そんなのあったんだ!みたいなものもあるかと思います
Unity初心者の方などはまずUnityで何ができるのか分からない場合も多いかと思いますので、この記事が開発のきっかけになれば幸いです


1.OculusRift,HTCVive

f:id:myudon:20171205203725j:plain f:id:myudon:20171205203746j:plain
まずは有名なヘッドマウントディスプレイ(HMD)であるこの2つです
用途ですが、主にはゲームをはじめとしたVRコンテンツの開発です、これを通してUnityの世界を自分の視界として捉えることができます
VR開発が盛んになり、こういったHMDが様々なコンテンツの開発で用いられるようになりましたね、値段も発売当初より安くなり企業だけでなく個人の開発者でも所持している人が多くなってきた印象です

https://www.oculus.com/

https://www.vive.com/jp/


2.LeapMotion

f:id:myudon:20171205203716j:plain
2つ目は安価で使いやすいLeapMotionです
用途ですが、簡単に言うと手のモーションを認識です マウスやコントローラーを介せずにそのまま手をかざし、手を動かすことで直感的に操作ができちゃいます
精度は高い・・・というほどではないですが、この値段で手のモーションを認識できるのであれば十分かなと思います(執筆時点で79ドルほど)
幾つか手のジェスチャー(例えば指でタップする)の判定があらかじめ用意してあり、初心者でもある程度のことができるデバイスですね

https://www.leapmotion.com/


3.Kinect

f:id:myudon:20171205203729j:plain
3つ目は体のトラッキングバイスで有名なKinectです
用途ですが、体のジェスチャーであったり、音声の認識です
3次元での認識することができるので、体全体を使ったゲームなどのコンテンツはもちろんのこと、体の支援システムや3次元復元といった研究分野でも大きく活躍しています
特に有名なのはモーションキャプチャーですね、ミクさんなどの3Dモデルに人間の動きを投影することでより柔軟な表現を可能にしています
(つい最近製造を終了してしまいました、サポートは継続するそうです)

https://developer.microsoft.com/ja-jp/windows/kinect


4.Muse

f:id:myudon:20171205203721j:plain
4つ目は変わり種Museです
用途はここまでとは打って変わり、脳波の状態の計測です
あまり普及はしていませんがUnityをサポートしています、公式サイトに導入の説明があるのでそちらを参考にすると良いかと
脳波を計測できるため医療分野での応用であったり、念じて操作するなど一風変わったコンテンツの開発にも使えるのではないでしょうか
ドッキリするコンテンツで脳波を計測してみるのも面白いかもしれませんね

http://www.choosemuse.com/


5.Theta

f:id:myudon:20171205203731j:plain
5つ目は全天球カメラThetaです
用途は、360°範囲の画像や動画の撮影です
カメラデバイスであれば基本的にUnityは認識することができるのですが、その中でもインタラクティブなのが全天球カメラですね
動画配信であったり、パノラマ画像であったりと多くの映像コンテンツで応用されています
中でも360°映像のライブ配信機能は面白く、お祭りや星空、はたまた海の中の配信など様々なコンテンツに応用されています

https://theta360.com/ja/


6.Hololens

f:id:myudon:20171205212127j:plain
6つ目は巷で話題の光学シースルーレンズであるHololensです
用途は、光学シースルーとホログラフィー技術を用いたMRコンテンツです
これを被ることで、仮想空間を映し出すのではなく、あくまでも現実空間にホログラム映像を投影することができます
MR(Mixed Reality)の名の通り現実空間を仮想空間を織り交ぜたコンテンツが作成可能で、とても未来的なデバイスだと思います(あんまり言うとxR警察に怒られるのでこのぐらいの説明で)
ただ、値段が少しネックで個人開発者(特に学生)には若干厳しいものとなっています

https://www.microsoft.com/ja-jp/hololens


7.UnlimitedHand

f:id:myudon:20171205203743j:plain
7つ目は個人的に可能性を感じるUnlimitedHandです
用途は手の筋肉の動きの検出、そして電気刺激による触覚のフィードバックです
簡単に言うと手を動かして触覚や衝撃を感じ取ることができるコントローラーです、電気信号なので疑似的ではありますが触覚型のコントローラーは珍しく大変価値のあるものだと思います
仮想世界の物に触れるといった、近未来的な発想を実現させる夢のあるデバイスです

http://unlimitedhand.com/


8.Tobii

f:id:myudon:20171205203735j:plain
最後のデバイスは学術分野での活躍が目立つTobiiです
用途はアイトラッキング、視線の計測です
使えないわけではないですが、ゲームだと若干用途が限定されてしまうかなと思います
先述の通り研究分野で活躍しており、中でも行動観察の分野では多く使われている印象です(スポーツ心理学など)
視線を活かしたコンテンツは少ない印象を受けるので、何かアイデアがあれば応用してみたいですね

https://www.tobiipro.com/ja/


いかがでしたでしょうか、長くなってしまいましたが、これらが自分が開発経験があったり興味を持っているデバイス達です
勿論紹介した以外にも様々なデバイスとUnityでの開発の試みがあります
インタラクティブなデバイスとUnityは相性がよく、ゲームだけでなく様々なコンテンツ開発にも応用できるのがわかったかと思います
みなさんもデバイスを用いて、新しい発想のアウトプットをしてみてください

UniRxとPhotonを用いた同期の実装

少し前からUnityの開発を手助けするライブラリとして有名になっているのがUniRxです

そしてオンラインゲームの開発エンジンとして有名なPhotonというものが存在します

今回はこの2つの軽い紹介と、実際に用いて同期ロジックを組み上げてみたものを紹介していきます

 

UniRx

詳しく説明するとキリがないのでかなりざっくりと説明します 

イベントや非同期処理を時間を軸としてフロー化し処理することで、ReactivePrograming(RP)を実現させている実装ライブラリのことをReactiveExtensions(Rx)と呼びます

元は.Netが提供していたライブラリでしたが、様々な分野で評価され、jsやSwift、kotlin等さまざまな言語でも実装がされています 

これをUnityリファレンスに向けて作ったのがUniRxというわけです 

 

Photon

Unityをはじめとして 様々なクロスプラットフォームで活躍するネットワーキングエンジンです

マルチプレイヤーでのマッチングシステムや同期などを簡単に実現することができるため、数多くのゲームで採用されています

Unityでマルチプレイヤーのゲームを作る際の定番ですね

 

実装

説明も軽くしたところで実装です

今回UniRxやPhotonのリファレンス自体の説明は省きますのでその点は自己補完よろしくお願いします

また、簡易的な仮実装なので実際はその開発環境や設計に沿った実装になります

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using Photon;
using Events;

public class PhotonRPCManager : Photon.MonoBehaviour {

    [SerializeField]
    private PhotonView _photonView;

    public Subject<TestInfo> OnRPCTest = new Subject<TestInfo>(); // イベントストリーム

    public void TestRPC(int damage, int time, int id, TestType type)
    {
        //外部からこれを呼ぶ
        _photonView.RPC("testRPC", PhotonTargets.All, damage, time, id, type);
    }

    [PunRPC]
    private void testRPC(int damage, int time, int id, TestType type)
    {
        //実処理、イベント通知
        OnRPCTest.OnNext(new TestInfo(damage, time, id, type));
    }

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

namespace Events
{
    public enum TestType { enemy, self }

    public struct TestInfo
    {
        public readonly int Damage;
        public readonly int Time;
        public readonly int Id;
        public readonly TestType Type;

        public TestInfo(int damage, int time, int id, TestType type)
        {
            Damage = damage;
            Time = time;
            Id = id;
            Type = type;
        }
    }
}

まずはRPC管理側の実装です

Subjectでイベントを管理、RPCでイベントを発行していきます

今回は適当な構造体を作って発行しています

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using Events;

public class TestModel : MonoBehaviour {

    [SerializeField]
    private PhotonRPCManager _manager;

    [SerializeField]
    private PhotonView _photonView;

    private int _damage = 100;
    private int _time = 10;
    private int _id = 0;

    private void Start()
    {
        _manager.OnRPCTest
            .Where(info => info.Type == TestType.self)
            .Subscribe(info => Debug.Log(string.Format("{0}:{1}:{2}", info.Damage, info.Time, info.Id)))
            .AddTo(this);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            Debug.Log(string.Format("EnemyEvent:{0}",_id));
            _manager.TestRPC(_damage, _time, _id, TestType.enemy);
            UpdateInfo();
        }

        if (Input.GetKeyDown(KeyCode.B))
        {
            Debug.Log(string.Format("SelfEvent:{0}", _id));
            _manager.TestRPC(_damage, _time, _id, TestType.self);
            UpdateInfo();
        }
    }

    private void UpdateInfo()
    {
        _damage += 100;
        _time += 10;
        _id++;
    }
}

続いて同期するモデルです、同期するモデル自体にはPhotonViewをアタッチせずに、ストリームを購読することによって同期を行います

また、購読の際にフィルタリングをかけて一部のイベントだけをトリガーとして処理するようにします、今回は仮のenumによって判定を行います 

ついでにイベントも簡易的に設定しました、今回は特定のキーを叩くだけですね 

今回はかなり簡易的に作っているので考慮がありませんが、フィルタリングやイベント通知に際して通知者をしっかりと設定する必要があります

(同期して生成した場合に1回のイベントを多重に呼ばせないため) 

f:id:myudon:20171014040756p:plain

一応結果です、Aキーを押した場合はイベントは起きていますがフィルタリングではじかれているため処理が呼ばれません、しかしBキーを押した場合は処理が呼ばれていることがわかります

 

このようにして同期オブジェクト側は、適宜同期イベントをストリームから購読し同期処理を行うといった仕組みになります 

簡易的かつ最低限の実装ですが、形としてはこういった感じですね 

利点や問題点

まず、利点です 

一番大きいのは同期処理をストリームとして処理できることでしょう 

マルチプレイにおける同期処理では様々なイベントが飛び交い、それらを正しく処理していく必要があります 

その際、ストリーム処理であれば、送られてきたイベントから様々な加工を施し処理を行うことができます 

遅延処理や、待機処理などを手軽に柔軟にできるのでこの点では大きく助かりますね 

 

次に問題点です 

まず本質から外れた問題点ですが、単純にRxを導入するのに様々なコストがかかること

パフォーマンス面もそうですし、導入コスト自体もあります 

そして設計の本質的な問題点ですが、様々なイベント処理に対応するにあたり機構が肥大化していくことです 

様々なパラメータが存在し、同期イベントが増えるたびにストリームとそれに呼応したメソッドを用意していかなければなりません 

共通パラメータが存在するのであれば複数イベントのストリームをまとめてしまいフィルタリングして取得することもできますが、結局ストリームが大きくなりすぎて発行するたびに無駄な記述も増えていくでしょう 

これは仮組なので大した肥大化はしないように見えますが、大規模な開発形態になりRPCが複雑に絡まってくるとこういった問題は浮き彫りになってきます 

 

以上をふまえて、開発のケースに合わせて適宜使っていきたいですね 

間違っているところの指摘や、これに対するコメントなどお待ちしております 

UnityにおけるDIパターンとZenject

DI、プログラミングにおける大事な概念の一つです、最近ちょこちょこ言葉を聞く機会が多くなったなと感じています。(PHPなどを触る方はご存知の方が多いでしょう)

自分も最近仕事の都合で、Unity+DIといった形態の開発をしています、まだ広まりが浅い気はしますが。

今回はその仕事の上で得た知見をまとめていこうかなと思います

 

DI(Dependency Injection)

そもそもDIってなんやねん、と

DIとはDependency Injection」の略で、直訳すると「依存性注入」という意味になります。

ゲーム界隈ではあまり聞きなれませんが、思想自体は結構前からあるものです

最近だとポケモンGOでDI思想によるアーキテクチャが採用されていたといった事例があり、Unity界隈では今ホットになってきたのかな?って感じがあります

 

実はこれ直訳するのはよろしくなく、あくまでもDependencyを注入するといった方が正しいのですが・・・まぁそれはさておき

じゃあDIってのはどういうことなの?と、いくつかのサイトでも紹介されていますが簡単に言うと「オブジェクトの提供」です(提供って書くと厳密には違う気がしなくもないですけど)

ある機能があったとして、それがあるオブジェクトのメソッドなりなんなりを使って機能している、これが一番簡単な「Dependency」です

hogeクラスがhugaクラスを持っていて、ある関数をhugaクラスの関数や変数に依存して使ったり、そんな感じ

 

 

今回はどちらかというとDIパターンとはというよりDIパターンをUnityで応用してみた、という試みのメモ書きなので、分からない人は調べてみてください

 

DIとUnityとZenject

じゃあDIをUnityでどう使うの?と

もちろん明示的に仕組みを組んで注入することはできますが、できればスマートに、労力なくやりたい

ってことで既存のUnity用DIフレームワークを使用します

今回使用したのは「Zenject」という無料のフレームワークです

 

github.com

 

ぶっちゃけC#用のDIフレームワークってちらほらあるんですけど(NinjectとかRx制作者のやつとか)Unityをターゲットにするとなるとあんまりないんですね

その中でもZenjectはかなりいい感じに使えるかなと思ったのでまとめていこうかなと

とはいっても紹介するのは触りだけです 

 

 まずヒエラルキーにSceneContextを用意しましょう、これはInstallerを管理したりするもの、と考えてもらえば大丈夫です

ヒエラルキーにオブジェクトを追加する感じでZenject→SceneContextというメニューがあると思うので、その手順でSceneContextを用意します

SceneContextはこんな感じ

f:id:myudon:20170916151649p:plain

 

 

次にInstallerを用意します、これは所謂注入係です

適当なスクリプトにMonoInstallerを継承しておけばよいです(ここについては後で少し捕捉します)

今回は何も書きませんが、ここでInstallBindingをoverrideし、注入についての設定などをしたりします

f:id:myudon:20170916152035p:plain

これを適当なオブジェクトにアタッチしておいてください、今回はInstallerというオブジェクトを用意しました

アタッチしたら、このInstallerを先ほどのSceneContextのInstallersの部分に入れていきます

f:id:myudon:20170916152805p:plain

 

では次に流し込むものを用意していきましょう、今回は適当な変数を持ったモデルを用意しました

f:id:myudon:20170916152143p:plain

 

これを適当なオブジェクトにアタッチして、ZenjectBindingというコンポーネントをアタッチしていきます

ZenjectBindingはBindingとついているように、流し込むコンポーネントをBindするコンポーネントです、Componentsの部分に今回流し込みたいGameModelを入れることでZenject側が自動で流し込む設定を行ってくれます

 

 

f:id:myudon:20170916152415p:plain

 

そしてこのGameModelを提供してもらうクラスを用意します(今回はReaderとしました)

受け取りたいクラスを変数として用意して、アトリビュートで[Inject]とつけてあげます

こうすることで、Zenject側が自動でこの_modelに、Bindingで指定したGameModelを流し込んでくれるようになります

f:id:myudon:20170916153059p:plain

 

SceneContext,Installer,GameModel,Readerの4つのオブジェクトがそろったところででは再生をしてみます、すると!

f:id:myudon:20170916153406p:plain

流し込んだ値を取得することができました!

このようにして、Injection周りを自分で書くことなく、オブジェクトを取得できるのです

 

Bindするためにシーンに置いとかないといけないじゃん、動的にやるにはどうするの?という疑問がわくかと思いますが、そもそもInstallerを用いた注入はあくまでもラップされた方法であり、動的にBindして注入することも全然可能です

その際コンテナにBindしてそれを流し込む(Resolve)といった一連の流れをケースに合うように書かないといけませんが・・・、まぁそれもそんなに手間じゃないので正直シングルトン参照とかよりよっぽど散らからないと思います

 

また、先ほどスルーしましたがSceneContextにあるPrefabInstallerならPrefab,ScriptableObjectInstallerならScriptableObjectをBindして流し込めちゃいます

Zenject様様ですね

 

Unity設計におけるDI思想

ここまでDIをUnityで!みたいなことを書いてきたわけなんですが実際どう有効なのか

 

例えばUnityで様々なゲームモデルのパラメータを扱うとき、よくシングルトンのマネージャクラスなどで置き、そこから取得するといった方法がよく使われると思います。

確かにシングルトンは便利なんですが、実質グローバルであり、かなりの密結合だといえます

依存関係なども分かりづらくなり、オブジェクト指向的な観点からも、おや?となる部分が多くなってしまいます

そういった点で、DI思想というものはグローバルにアクセスするのではなく、あくまでモジュール単位に切り離してオブジェクトを渡せば良いため、密になる部分を減らすことができます。

 

より良い設計を、より柔軟な設計を、と追い求めていくならば、Unity設計において知っておいて損はないと思います(かといってなんでもかんでも注入すればいいじゃんとなってコンポーネント思想がぐらつくのはあれですが)

 

正直自分も学びたての設計なので、突っ込みどころがあるかと思いますが、その時はコメントでガンガン突っ込んでください、勉強になります

 

後、DIといえばパフォーマンス関係も気になるところで、その点においてRx制作者の方が作っていた「MicroResolver」も試してみたいところですね

github.com

 

 

長ったらしくなりましたが、ようはZenject使うと捗るよってことです

意見やコメントお待ちしております

 

参考にしたリンク

DIとは?DIコンテナとは?試してみた(前編)[PHP][DI] - あざらし備忘録。

 

DI・DIコンテナ、ちゃんと理解出来てる・・? - Qiita

 

neue cc - MicroResolver - C#最速のDIコンテナライブラリと、最速を支えるメタプログラミングテクニック