【さちゃでもわかる】UniRx導入編

## はじめに
バイト先でUniRxを用いた開発に携わっていましたが，まだまだ理解ができていないと常々思っていました．
そしていつか自分で1から導入してみたいなと思っていたのでやってみました．その備忘録です．
これからUniRxを導入したい，学びたいと思っている人の参考になればと！

## そもそもUniRxとは？
ほとんどは以下のリンクをしっかり読めばわかると思います．(自分も完全に理解しているわけではないので，確かなことは言えませんが)

参考：[UniRx入門シリーズ 目次](https://qiita.com/toRisouP/items/00b8a5bb8e7b68e0686c)

個人的な理解だと，
「UniRxはevent機能の上位互換」で
「イベントの発火条件の登録とイベントの内容が登録でき」て
「フィルタリングが簡単」
って感じです！！

一応上記の記事での説明を抜粋すると，

> UniRxとは、[neuecc](https://twitter.com/neuecc)さんが作成されているReactive Extensions for Unityなライブラリです。

>Reactive Extensions（以下Rx)は、要点だけ箇条書きすると次のようなライブラリとなっています。
・MicrosoftResearchが開発していたC#向け非同期処理向けライブラリ
・デザインパターンの1つ、Observerパターンをベースに設計されている
・時間に関係した処理や、実行タイミングが重要となる処理を簡単に記述できるようになっている
・完成度が高く、Java,JavaScript,Swiftなど様々な言語に移植されている

となっています，パッと見だと何言ってるかわからないと思うのであまり深く考えず後々理解できればいいかくらいで進めようと思います．

## 便利だなと思った実装
- ユーザ名の変更(変更があったかどうかで通信の有無を決められたり)
- 長押しやダブルクリックの判定
- ストリームの結合

などなど，他にも実装方法はあるが比較的簡単に実装ができる．．．はず！

## 参考になりそうなリンク
参考：[UniRx入門シリーズ 目次](https://qiita.com/toRisouP/items/00b8a5bb8e7b68e0686c)
参考：[UniRxを導入するメリット ～こういう時にUniRxは使えるよ～](https://qiita.com/Marimoiro/items/2ad8a1b422a3fe98f938)
参考：[UniRx 知らないと人権が無い気がしてきたので勉強した。](https://qiita.com/kingyo222/items/e02b6d70a9ab24ff3de6)
参考：[UniRxのシンプルなサンプル その6(購読の停止)](https://qiita.com/Marimoiro/items/819ddb3e68aab7ee3b95#addto)

## 実装環境
macOS Catalina 10.15.4
Unity 2018.4.22f1
UniRx 7.1.0

## インストール
Asset Storeで『UniRx』と検索します．
すると『UniRx - Reactive Extensions for Unity』が出てくるはずなので，Downloadします．(Unity IDの新章が求められる場合がありますが，それはやってください)
その後，DownloadボタンがImportボタンに変わっているので，Importボタンをクリックします．
Projectを確認すると`Assets > Plugins`配下にUniRxが追加されています．
これでUniRxの下準備完了．早速使っていきましょう！

## お試しUniRx
簡単にボタンを押すごとにカウントアップする仕組みを作っていきましょう！
まずはUIの準備します！
今回は使う頻度が高そうな，`Button`,`Text`,`InputField`を置いてみました！

こんな感じにしましたが，正直適当でいいです．`Canvas`配下に`Button`,`Text`,`InputField`があれば問題なしです！
あと，SampleControllerはUniRxのイベント登録とかUIへの紐付けを管理するためのスクリプトを置く場所として用意しました！

<img width="400" alt="スクリーンショット 2020-05-03 17.49.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/1f5c7140-9355-e63d-3677-c1dca4d0c52a.png">
<img width="400" alt="スクリーンショット 2020-05-03 17.49.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/a91ddeaa-64e9-a9d5-4408-a1f75f81ff6f.png">

このあたりつまずくことはあまりないと思いますが，わからない人は以下の参考リンクから勉強してみてください！

参考：[【uGUI】Buttonの使い方](https://qiita.com/2dgames_jp/items/b3d7d204895d67742d0c)

次に，主題でもあるUniRxのスクリプトを作っていきましょう！
適当な名前ControllerとなるC#のファイルを作成します！(UniRxUITestってクソみたいな名前でもOKです)

<img width="654" alt="スクリーンショット 2020-05-03 17.57.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/28a2d9dc-f504-f23c-09fc-656bcda33575.png">

作成できたら，このファイルを開いて編集していきます！
まず，必要なのは`UniRx`のインポートですので

``` C#
using UniRx;
```

を追加し，UIの紐付けやカウントアップのためのコードを追加します．
具体的にはこんな感じです！

``` C#
using System;
using UnityEngine;
using UniRx;
using UnityEngine.UI;

public class UniRxUITest : MonoBehaviour
{
    // UIとの紐付けのため
    [SerializeField] private Button button;
    [SerializeField] private InputField inputField;
    [SerializeField] private Text countText;

    // カウントを記録する
    private int count = 0;

    void Start()
    {
        countText.text = count.ToString();
        Setup();
    }

    private void Setup()
    {
        // buttonのイベントが発行されたときにカウントアップmethodが走る
        // OnClickAsObservableはUniRxのプラグインのなかで定義されている
        // 自分で定義を追加することもできる(別の記事書いたらやってみます)
        button.OnClickAsObservable()
            // クリックイベントの最後に呼ばれるのがSubscribe
            // ラムダ式で記入している．_が引数で(今回はないので仮引数の_)呼ばれるのがCountUp()
            // Addto()はいつこのイベントを破棄するかを決めている．詳しくは別記事か参考リンクから
            .Subscribe(_ => CountUp())
            .AddTo(this);
    }

    private void CountUp()
    {
        count++;
        countText.text = count.ToString();
    }
}

```

これでスクリプトはとりあえずOKなのでこれをSampleControllerに紐付けます！
そして，それぞれのUIをスクリプトにドラック&ドロップで紐付けます！
<img width="400" alt="スクリーンショット 2020-05-03 18.16.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/d14a7d07-2ffc-3ddc-70c1-2e6fdd701003.png">

変なところに空白が入っていますがこれは自分のミスなので無視していただけると嬉しいです．．．

ともあれこれで準備は整ったので実際にプレイしてみましょう！

![Unity_CountUp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/b5b4c1ad-5677-d60e-bfcb-9fe2c5f2a692.gif)

小さくて少し見づらいかもれないですがカウントアップしているのがわかると思います．

次に，もう少しだけUniRxっぽいことをしていきます！
`InputField`に入力した値で挨拶できるようにします．
下記のようにコードを修正してみます！

``` C#
using System;
using UnityEngine;
using UniRx;
using UnityEngine.UI;

public class UniRxUITest : MonoBehaviour
{
    [SerializeField] private Button button;
    [SerializeField] private InputField inputField;
    [SerializeField] private Text countText;
    [SerializeField] private Text greetText;

    private int count = 0;
    
    // ここが重要！！
    // SubjectはIObservableとIObserverの2つを実装しており，「値を発行する」「値を購読できる」という2つの機能を持ったクラスである
    private Subject<string> _onClickButton = new Subject<string>();
    // IObservableはイベントメッセージを購読できる」というふるまいを定義したインターフェース
    public IObservable<string> OnClickButton
    {
        get { return _onClickButton; }
    }

    void Start()
    {
        countText.text = count.ToString();
        Setup();
    }

    private void Setup()
    {
        button.OnClickAsObservable()
            .Subscribe(_ => CountUp())
            .AddTo(this);
        
        // インプットフィールドの入力が終わったらイベント発火
        inputField.OnEndEditAsObservable()
            .Subscribe(text => _onClickButton.OnNext(text))
            .AddTo(this);
        
        // 作成した_onClickButtonの値が変わったらイベント発火
        OnClickButton
            .Subscribe(text => Greet(text))
            .AddTo(this);
    }

    // カウントアップのメソッド
    private void CountUp()
    {
        count++;
        countText.text = count.ToString();
    }

    // 挨拶のメソッド
    private void Greet(string name)
    {
        greetText.text = "おはようございます" + name + "さん";
    }
}

```

先ほど同様，Unity側でUIとスクリプトの紐付けを行います．
<img width="530" alt="スクリーンショット 2020-05-03 18.59.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/2b979e8b-f4b2-36a8-c197-1502741dbce2.png"><img width="300" alt="スクリーンショット 2020-05-03 18.59.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/eca90ca6-c277-cc84-d364-72b813036be3.png">
こんな感じになっていればOKです！

実際にプレイしてみます．
![Unit_Greet.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453529/03258a28-ff74-322e-97b3-a0f7e976c85e.gif)

入力フォームの編集が終わった際にテキストが更新されることがわかります．これはGreetのメソッドが呼ばれているからですね！
ここではアルファベットの入力以外が弾かれてしまいますが，これはUniRxとは直接関係ないので気になる方は以下の参考リンクから調べてみてください！

参考：[【Unity入門】InputFieldに入力された文字列をテキストに反映させよう！](https://mogi0506.com/unity-inputfield/)

簡単にいうと`InputField`の__LineType__を__Multi Line NewLine__に変えるだけです！やったね！

## 最後に
最後までお読みになってくださりありがとうございました！
結局，実際の動作だけを追っているだけで説明の少ないものになってしまいました．すみません...
それに不用意にイベントを使っているとこもあるので決して真似すべきコードではないと思いますが，少しでも参考になれば嬉しいです！！
自分もこれから勉強しながら都度アウトプットできればいいと思っているので，一緒に勉強していきましょう！