UniRxを勉強しよう

きれいなコードとか途中のものも多いけれど、今回転職先の先輩から「UniRxを使えるようになってほしい」ということでUniRxを活用した電卓を作るよう課題を出してもらった。

というわけで、unityを使って電卓を作ってみる。
以前C#のフォームアプリケーションで作ったことはあったが、UniRxを使うとどうなるのか試していく。


とりあえず画面だけは昨日のうちに作っておいた。

f:id:dkkng:20200715234410p:plain
Unityで作った電卓

見てくれは後々修正する。

さて、きちんと勉強するなら「UniRxについて理解する」ことから始めるべきだが、僕はこういうのがめちゃくちゃ苦手&課題の納期的にも「先人のやり方を要所要所で模倣しながら並行して理解する」という方式で行こうと思う。

電卓を作る際のロードマップとしては下記のようなイメージだ。
1. まずは簡単に見た目だけ作る
2. ボタンを押下した際にこれを検知する
3. 押下されたボタンから数値や記号を取得する
4. 引数に渡された数値がディスプレイに表示されるようにする
5. 検知した数値や記号から四則演算を実施できるようにする
6. 見てくれを整える
7. 書き出す

1. は昨日のうちにやったので、今日は2.を実施できるようにしたい。

というわけで、下記の記事をとりあえず丸パクリして動きを確認してみた。
qiita.com

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

public class PushedButton : MonoBehaviour
{
    [SerializeField] Button button;
    [SerializeField] Text text;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void Awake()
    {
        button.onClick.AsObservable()
            .Select(_ => 1)
            .Scan(0, (element, acc) => element + acc)
            .Subscribe(count => text.text = count.ToString())
            .AddTo(gameObject);

    }
}

これにより、ボタンを押下した際にボタンの子オブジェクトであるテキストの値が1ずつ増分されることを確認した。

f:id:dkkng:20200715235358p:plain
0のボタンを押下すると値が0,1,2...と増えていく

引用元にも解説が載っているが、知識ゼロで読んでも意味が分からなかった。
では、このスクリプトについて調べていく。

なお、「初級者が新しい知識を習得する際の情報の流れ」を記録しておくため、以下は体系的にまとめる上ではガッタガタな(例えば[具体]から[抽象]に記述が進むなど)書き方をする。まあ僕しか見ないからいいんだけど。

void Awake()

startやupdateはなじみ深いが、こいつは初めて見た気がする。
awakeはstartよりも先に実行されるメソッドで、シーンの開始時点で読み込まれるらしい。
このサンプルコードでなぜawakeにこの処理が記載されているのかは分からないが、Unityの公式リファレンスを見ると「Startの中で使う関数等をawakeの中に書いておくと、Startでその関数を呼び出せたりするよ」という例が載っていた。
「初期化の内容はここに書いておくといいよ」的な意味合いなのかな?

button.onClick.AsObservable()

この行では、ボタンオブジェクトのonClickイベントをIObservableという型に『アップキャスト』しているらしい。

アップキャスト…派生クラスから基底クラスに型を変更(キャスト)すること。
"Observable"という通り、observerから観測可能にするということだ。
これによってイベントの検知ができるようになる…らしい。

ちょっと違いました

…と思って調べてたら、IObserverとIObservableの解説記事が出てきた。
「UniRxはイベントの上位互換」らしく、イベントよりいろいろ柔軟に使えるらしい。
UniRxでのイベント検知(厳密には違うが分かりやすいのでこう書いておく)は「Subject」というやつが中核をなして行われる。

  • Subscribe : メッセージの受け取り時に実行するを関数を登録する
  • OnNext : Subscribeで登録された関数にメッセージを渡して実行する

といった仕組みになっているらしい。
OnNextで送り出されたメッセージを、Subscribe側が受け取って実行する、この際の橋渡しというか楔になっているという話だと理解した。

OnNext、SubscribeはSubjectが持つ二つのインターフェースに含まれるメソッド

上記は理解しやすくするための簡略化された説明だった。
実際にはSubjectはIObserverとIObservableの二つのインターフェースを持っている。
このうち、OnNextを有するIObserverはイベントの発行者としてふるまうインターフェースで、Subjectを有するIObservableはイベントメッセージの購読(受け取り)者としてふるまうインターフェースになっている。

長くなったが、

button.onClick.AsObservable()

によって、onClickはIObservableにキャストアップされ、これによりイベント発生時(正確にはsubjectがイベントを検知した時)にどんなふるまいをするか決められるようになったということだ。

ん?じゃあこの場合のIObserverはどこにあるんだ…?そもそもOnClickってSubjectクラスなのか?

今日はもう遅いので一旦ここまでにしよう…

【参考にしたサイト/記事】
docs.unity3d.com

qiita.com

qiita.com

qiita.com

qiita.com