【Unity】次世代のUniRx「R3」を導入してみる

Unity 2022.3.16
R3 0.1.2

はじめに

2024年1月9日、Cysharp社からR3というライブラリがプレビュー公開されました。

github.com

UnityでReactive Extensions(Rx)を実現するライブラリとしては既にUniRxがありました。UniRxもCysharp社の代表を務められているneueccさんがリリースされているライブラリになっています。 github.com ただ、最新版である7.1.0のリリースは2020年2月26日とほぼ4年前でそれ以降新機能の追加やUnity・C#の更新に伴うパフォーマンス向上のアップデートは行われておらず、個人的にはUniRxの更新ないしRxの実現を図るハイパフォーマンスなライブラリの登場は待ち望んでいたところでした。R3自体はUnityでの使用に限定されたものではなく、UniRxとの完全な互換性があるわけでもありませんが、Unityに統合するためのパッケージも同時に提供されておりUnityを使用する上ではUniRxの進化版ライブラリといえそうです。
具体的に自分が更新を望んでいた機能の例として、AddToという拡張メソッドの存在があります。AddToメソッドはIDisposableに対する拡張メソッドの形で定義されており、ストリームの購読破棄をゲームオブジェクトの破棄タイミングに紐づけて行えるという非常に便利な機能を提供してくれます。以下のサンプルコードはかなり恣意的なものですが、AddToメソッドを用いることでsampleStaticSubjectに対して購読と購読破棄をメソッドチェーンの形で記述できています。

using UniRx;
using UnityEngine;

public sealed class AddToTest : MonoBehaviour
{
    private static readonly Subject<Unit> sampleStaticSubject = new();

    private void Start()
    {
        sampleStaticSubject
            // 購読
            .Subscribe(_ => Debug.Log("Test"))
            // 購読破棄をゲームオブジェクトの破棄と同時に行う
            .AddTo(this);

        sampleStaticSubject.OnNext(Unit.Default);
    }
}

一方でこのAddToメソッドを使用すると、実行時にゲームオブジェクトに対してObservableDestroyTriggerという購読しているストリームを管理するためのコンポーネントが自動的にアタッチされます。 これは従来のUnityの仕組み上このような形で実装せざるを得なかったと思いますが、できればゲームオブジェクトに余計にコンポーネントを増やすことは避けたいところです。しかしUnity 2022.2からMonoBehaviourにdestroyCancellationTokenというCancellationToken型のプロパティが追加され、これを用いることでコンポーネントを増やすことなく購読の寿命の紐付けが簡易かつハイパフォーマンスに行えるようになりました。(非同期処理の文脈においてですが、以下のUnity公式の動画でdestroyCancellationTokenについて軽く触れられています。)

youtu.be

新しいR3ではここについても現代化が図られています。先ほどのサンプルと同様のコードをR3を使って書くとこんな感じになります。

using R3;
using UnityEngine;

public sealed class AddToTest : MonoBehaviour
{
    private static readonly Subject<Unit> sampleStaticSubject = new();

    private void Start()
    {
        sampleStaticSubject
            // 購読
            .Subscribe(_ => Debug.Log("Test"))
            // 購読破棄をゲームオブジェクトの破棄と同時に行う
            .AddTo(this);

        sampleStaticSubject.OnNext(Unit.Default);
    }
}

実際、using UniRx;using R3;に書き換わっただけで他の部分は完全に同じです。ですがR3の方のAddToは以下のように内部的にdestroyCancellationTokenに対する紐付けをする実装に変わっており、管理用のコンポーネントがアタッチされたりすることはないコスパの良いものになっています。

public static CancellationTokenRegistration AddTo(this IDisposable disposable, MonoBehaviour value)
{
    return disposable.AddTo(value.destroyCancellationToken);
}

上記であげた例は非常に表層的なもので、実際には抜本的な設計の変更や大幅なパフォーマンス向上、ストリームの購読状況が可視化できるTracker Windowの付属など聞いただけでわくわくするような機能が多く盛りこまれているライブラリになっています。R3のGitHubリポジトリにあるREADMEには詳細についてまとめられているため、そちらを読めば大体の内容がわかると思います。R3の具体的な進化点については調査中のところもあるので、また別記事にまとめさせていただきたいと思います。
R3はUniRxと導入方法(配布形式)が変わっているため、この記事ではUnityにR3を導入するところまでを行ってみます。

注意

R3はプレビュー段階のライブラリです。バグが含まれていたりAPIが大きく変更されたりする可能性が十分にあるので、プロジェクトに導入する際はバックアップを取るなどの準備を行ってからにした方が良いでしょう。

インストール

R3はNuGetパッケージとして配布されています。

www.nuget.org

ここから直接dllをダウンロードしてくるのも良いのですがアップデートが面倒だったり依存しているパッケージもあったりするので、今回はR3のREADMEで紹介されているようなNuGetForUnityを使ったインストール方法にします。

NuGetForUnityのインストール

NuGetForUnityはNuGetのパッケージをUnityへ簡単に導入することができるようにするライブラリです。

github.com

この記事ではOpenUPM経由でインストールしますが、git urlでも問題なく入れることができます。
Project SettingsからPackage Managerのタブを開き、Scoped Registryとして以下のように入力し、Applyを押します。

Name OpenUPM(任意の名前)
URL https://package.openupm.com
Scope(s) com.github-glitchenzo.nugetforunity

これでPackage Managerの選択肢にMy Registriesが追加されます。その後Window/Package ManagerからPackage Managerを開きMy Registriesを選択、表示されているNuGetForUnityをインストールします。

R3(コア部分)のインストール

次にR3のコア部分をインストールします。NuGetForUnityのインストールが成功していればUnityのツールバーにNuGetの表示が増えているはずなので、そこからManage NuGet Packagesを開き検索バーに入力されているSearchの文字をR3に置き換えてSearchを押します。余談ですが、NuGetForUnityを使う際プレースホルダとしてのSearchの文字がラベルではなく実際に入力されている文字なのがいつも気になります。 表示された中からR3 by Cysharpとなっているパッケージを見つけ、インストールします。2024年1月11日現在のバージョンは0.1.2のようです。

R3(Unity統合部分)のインストール

最後にR3のUnityに対する機能を提供する部分をインストールします。まだOpenUPMでの提供は行われていないため(プレビュー版ということもあり今後提供されるかも不明です)、git url経由でインストールします。またWindow/Package Managerを開き、Add package from git URL...を選択して出た入力欄にhttps://github.com/Cysharp/R3.git?path=src/R3.Unity/Assets/R3.Unityと入力してAddします。 これでR3のUnity統合部分もインストールされ、使用する準備が整いました。