[Unity] UniRxをR3に移行する
はじめに
UnityのRxライブラリとしてUniRxを使っている方は多いと思います。後継ライブラリであるR3が登場し、UniRxは今後更新されないようです。今回はUniRxを使っていたプロジェクトをR3に移行させた手順について解説します。
参考記事
書き換えもとになるUniRxのコード
UniRxを使ったコードでまず挙動を確認します
using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
public class UniRxSample : MonoBehaviour
{
//値が変更されたらイベントが発火するReactiveProperty
ReactiveProperty<int> _reactiveProperty = new ReactiveProperty<int>(0);
//外部のクラスにはReadOnlyReactivePropertyで公開
public IReadOnlyReactiveProperty<int> ReadOnlyReactiveProperty => _reactiveProperty;
//またはIObservableで公開
public IObservable<int> OnValueChanged => _reactiveProperty;
void Start()
{
//値が更新されたらDebug出力
_reactiveProperty.Subscribe(x => Debug.Log(x)).AddTo(this);
_reactiveProperty.Value = 1;
_reactiveProperty.Value = 2;
//これは出力されない
_reactiveProperty.Value = 2;
_reactiveProperty.Value = 3;
//強制的に通知
_reactiveProperty.SetValueAndForceNotify(3);
//マウスを押下したらDebug出力
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Subscribe(_ => Debug.Log("GetMouseButtonDown"))
.AddTo(this);
//Spaceキーを押下したらDebug出力(UniRx.Triggers)
this.UpdateAsObservable()
.Where(_ => Input.GetKeyDown(KeyCode.Space))
.Subscribe(_ => Debug.Log("GetKeyDown Space"))
.AddTo(this);
//TransformのPositionが変更されたらDebug出力
this.transform.ObserveEveryValueChanged(t => t.position)
.Subscribe(x => Debug.Log($"PositionChanged:{x}"))
.AddTo(this);
//ReactiveCollectionでAdd/Remove/Replaceを監視
var collection = new ReactiveCollection<int>();
collection.ObserveAdd().Subscribe(x => Debug.Log($"Add:{x}")).AddTo(this);
collection.ObserveRemove().Subscribe(x => Debug.Log($"Remove:{x}")).AddTo(this);
collection.ObserveReplace().Subscribe(x => Debug.Log($"Replace:{x}")).AddTo(this);
collection.Add(1);
collection.Add(2);
collection[0] = 3;
collection.Remove(2);
}
}
出力
0
1
2
3
3
PositionChanged:(0.00, 1.00, -10.00)
Add:Index:0 Value:1
Add:Index:1 Value:2
Replace:Index:0 OldValue:1 NewValue:3
Remove:Index:1 Value:2
#マウスをクリック
GetMouseButtonDown
#スペースキーを押下
GetKeyDown Space
#アタッチしたオブジェクトのPositionを変更
PositionChanged:(0.00, 1.00, 0.00)
R3のインストール
Package Manager経由でR3をインストールします。まずEdit->Project Settings->Package Managerを開きます。ここでScoped Registriesに2つのURLを登録します
Name: Unity NuGet
URL: https://unitynuget-registry.azurewebsites.net
Scope(s): org.nuget
Name: OpenUPM
URL: https://package.openupm.com
Scope(s): com.cysharp
次にWindow->Package Managerを開き、Packages:をMy Registries
に切り替えます。ここで検索ボックスにR3
と入力すると2つのリポジトリが出てくるので両方ともインストールします
これでR3のインストールは完了です。もしプロジェクト内でReactiveCollection
または ReactiveDictionary
を使っている場合は、以下に示す手順でObservableCollectionsのインストールも行ってください。
PackageManagerを開きObservableCollections
で検索を行いObservableCollections(NuGet)
とObservableCollections.R3(NuGet)
をインストールします。下方に出ているものはバージョンが古いものなのでインストールしないようにご注意ください。
UniRxからR3へ書き換えを行う
UniRxとR3が共存している状態は良くないのでUniRxを削除します。Plugins/UniRx
のフォルダごと削除すればUniRxの削除は完了です。
削除した直後はコンパイルエラーが出るので書き換えていきます。
修正したコードが下記のものになります。
using R3; //UniRxから書き換え
using R3.Triggers; //UniRx.Triggersから書き換え
using ObservableCollections; //ObservableListを使うために追加
using UnityEngine;
//using System; //Systemをusingするのは不要になった
public class UniRxSample : MonoBehaviour
{
ReactiveProperty<int> _reactiveProperty = new ReactiveProperty<int>(0);
//外部のクラスにはReadOnlyReactivePropertyで公開
public ReadOnlyReactiveProperty<int> ReadOnlyReactiveProperty => _reactiveProperty;
//またはObservableで公開
public Observable<int> OnValueChanged => _reactiveProperty;
void Start()
{
//値が更新されたらDebug出力
_reactiveProperty.Subscribe(x => Debug.Log(x)).AddTo(this);
_reactiveProperty.Value = 1;
_reactiveProperty.Value = 2;
//これは出力されない
_reactiveProperty.Value = 2;
_reactiveProperty.Value = 3;
//強制的に通知
_reactiveProperty.OnNext(3); //SetValueAndForceNotifyの代わりにOnNextを使う
//マウスを押下したらDebug出力
Observable.EveryUpdate()
.Where(_ => Input.GetMouseButtonDown(0))
.Subscribe(_ => Debug.Log("GetMouseButtonDown"))
.AddTo(this);
//Spaceキーを押下したらDebug出力(R3.Triggers)
this.UpdateAsObservable()
.Where(_ => Input.GetKeyDown(KeyCode.Space))
.Subscribe(_ => Debug.Log("GetKeyDown Space"))
.AddTo(this);
//TransformのPositionが変更されたらDebug出力
//UniRxとは書き方が異なる
Observable.EveryValueChanged(this.transform, t => t.position)
.Subscribe(x => Debug.Log($"PositionChanged:{x}"))
.AddTo(this);
/*
* UniRxでの書き方
this.transform.ObserveEveryValueChanged(t => t.position)
.Subscribe(x => Debug.Log($"PositionChanged:{x}"))
.AddTo(this);
*/
//ObservableListでAdd/Remove/Replaceを監視
var collection = new ObservableList<int>(); //ReactiveCollectionの代わりにObservableListを使う
collection.ObserveAdd().Subscribe(x => Debug.Log($"Add:{x}")).AddTo(this);
collection.ObserveRemove().Subscribe(x => Debug.Log($"Remove:{x}")).AddTo(this);
collection.ObserveReplace().Subscribe(x => Debug.Log($"Replace:{x}")).AddTo(this);
collection.Add(1);
collection.Add(2);
collection[0] = 3;
collection.Remove(2);
}
}
細かく見ていきます
using
using UniRx
からusing R3
に変わります。Triggersも同じように書き換えます。下記で説明するObservableList
を使う際はusing ObservableCollections
も追加します。また、IObservable
のために記述していたusing System
は不要になります
IReadOnlyReactiveProperty / IObservable
IReadOnlyReactiveProperty
が廃止されており、代わりにReadOnlyReactiveProperty
を使うように変更されています。また、Observable
がSystemではなくR3で再定義されたものを使うようになった影響によりIObservable
はObservable
に書き換えます。
また、IReadOnlyReactiveProperty
で値にアクセスする際は.Value
を使っていましたが、.CurrentValue
に変更されています。ちなみにReactiveProperty<T>
にはget/setができる.Value
とgetのみの.CurrentValue
二つのプロパティが用意されています。
SetValueAndForceNotify
ReactivePropertyの変更が同じ値であっても通知を行うSetValueAndForceNotify
が廃止されました。代わりにOnNext
を使うと同じ挙動になります。
ObserveEveryValueChanged
値が変化した際に通知を行うObserveEveryValueChanged
は記述が大きく変わりました。オブジェクトからメソッドを生やしていたのが、Observable.EveryValueChanged
の第一引数にオブジェクトを入れる形になります。
ReactiveCollection / ReactiveDictionary
ReactiveCollection
の代わりにObservableList<T>
, ReactiveDictionary
の代わりにObservableDictionary<TKey, TValue>
が用意されています。ほかにも ObservableHashSet<T>
, ObservableQueue<T>
, ObservableStack<T>
, ObservableRingBuffer<T>
, ObservableFixedSizeRingBuffer<T>
があるようです。
ハマったところ
ObservableListのObserveAdd()などのメソッドが見つからない
実はPackage Managerの方にもObservableCollections
が存在し、こちらをインストールした場合、拡張メソッドの紐づけがうまくいきません。結果、ObserveAdd()
などのメソッドが見つからずコンパイルエラーになってしまいます。
これを防ぐために、ObserveAdd()
などのイベントを使いたい場合は、ObservableCollections
とObservableCollections.R3
両方ともNuGet
経由でインストールしましょう。
まとめ
UniRxからR3へ移行するためには、書き換えなければならない場所が数多くあります。しかし、ObservableTracker
というリークを防ぐ仕組みが追加されていたり、実行速度が上がったりとメリットは大きいです。もし書き換えるチャンスがあるようでしたら書き換えを検討してみてはいかがでしょうか?
Discussion
UnityNuGetに
ObservalbeCollection
とObservalbeCollection.R3
を追加してもらいました。 デプロイに数時間かかり月1回くらいしか更新していないので来月あたりにPackage Manager経由でインストールできるようになると思います。これでインストールがやりやすくなりますね!
UnityNuGetのサーバーが更新されてObservableCollectionとObsrevableCollection.R3もPackage Managerからインストールできるようになりました
報告ありがとうございます!
記事も書き換えておきますね