安装

方式一:
1.unity包管理器安装NuGetForUnity
2.从NuGet打开窗口 -> 管理NuGet包,搜索“R3”并按安装。

方式二:
通过git URL直接安装:
https://github.com/Cysharp/R3.git?path=src/R3.Unity/Assets/R3.Unity

反应式X(Reactive X)

    ReactiveX 是一个库,用于使用可观察序列编写异步和基于事件的程序。它扩展了观察者模式以支持数据和/或事件序列,并添加了运算符,允许您以声明方式将序列组合在一起,同时抽象出对低级线程、同步、线程安全、并发数据结构和非阻塞 I/O 等问题的关注。

ReactiveX的操作符

  • 创建可观察序列:
    创建新事件源的操作符。
    • Create : 通过调用观察者的方法从无到有创建一个事件源
    • Defer : 在观察者订阅之前不会创建事件源,并为每个观察者创建一个新的事件源
    • Empty/Never/Throw : 创建具有非常明确和有限行为的事件源
    • From : 将一些其他对象或数据结构转换为事件源
    • Interval : 创建一个事件源,它以给定的时间间隔发出一系列整数
    • Just : 将对象或一组对象转换为发出该对象或那些对象的事件源
    • Range : 创建一个事件源,它发出一系列连续整数,从指定的开始值到指定的结束值
    • Repeat : 创建一个事件源,重复发出特定事件或事件序列
    • Start : 创建一个发出函数返回值的事件源
    • Timer : 创建一个事件源,它在指定的时间间隔后发出一个值
  • 转换事件源:
    转换事件源发出的事件的操作符。
    • Buffer : 周期性的将事件源发出的事件收集成捆并发出这些捆绑事件,而不是一次发送一个事件
    • FlatMap : 将事件源发出的事件转换为多个事件源,然后将这事件的依次发出
    • GroupBy : 将一个事件源根据不同的事件按key划分为一组事件源
    • Map : 每个事件源发出的事件通过将函数处理后在发出
    • Scan : 依次的用聚合函数处理事件源发出的事件, 并发出每个连续的值
    • Window : 将事件源中的事件周期性划分为事件源窗口并发出这些窗口,而不是一次发出一个事件
  • 过滤事件源:
    从源事件源有选择地发出事件的操作符。
    • Debounce : 如果特定的时间跨度已经过去而没有发出另一个事件则从事件源发出一个事件
    • Distinct : 过滤掉重复的事件
    • ElementAt : 仅从事件源发出位置n的事件
    • Filter : 过滤掉不符合条件的事件
    • First : 仅从事件源发出第一个符合条件的事件
    • IgnoreElements : 丢弃事件源发出的事件,只保留完成通知
    • Last : 仅从事件源发出最后一个符合条件的事件
    • Sample : 周期性的从事件源发出最近的事件
    • Skip : 跳过事件源发出的前n个事件
    • SkipLast : 跳过事件源发出的最后n个事件
    • Take : 只从事件源发出前n个事件
    • TakeLast : 只从事件源发出最后n个事件
  • 组合事件源:
    通过合并多个源事件源创建一个事件源的操作符。
    • And/Then/When : 使用Pattern和Plan中介组合两个或多个事件源发出的事件
    • CombineLatest : 当两个事件源中的任何一个发出一个事件时,通过指定的函数组合每个事件源发出的最新事件并发出
    • Join : 在另一个事件源发出的事件定义的时间窗口期间发出一个事件源中的事件,组合两个事件源发出的事件
    • Merge : 将多个事件源合并为一个事件源,并发出所有事件
    • StartWith : 在事件源发出第一个事件之前发出一些初始值
    • Switch : 切换到另一个事件源,取消订阅当前事件源并订阅新事件源
    • Zip : 将两个事件源中的事件按顺序组合成元组并发出
  • 错误处理:
    有助于捕获事件源的错误通知的操作符。
    • Catch : 捕获事件源中的错误并将其转换为另一个事件源发出的事件
    • Retry : 重新订阅事件源,直到成功或达到最大重试次数
  • 公共操作符:
    用于处理事件源的有用操作符的集合。
    • Delay : 延迟事件源发出的事件
    • Do : 在事件源发出事件时执行指定的动作
    • Materialize/Dematerialize : 发出表达事件源发出的事件(通知)类型,和逆操作
    • ObserveOn : 指定观察者将观察此事件源的调度程序
    • Serialize : 强制事件源进行序列化调用并保持良好行为和同步
    • Subscribe : 根据事件源的发出的事件或通知进行操作
    • SubscribeOn : 指定事件源在订阅时应使用的调度器
    • TimeInterval : 将发出事件的事件源转换为发出这些事件之间的时间间隔
    • Timeout : 镜像源事件源,但如果在指定时间段内没有任何发出的事件,则发出错误通知
    • Timestamp : 为事件源发出的每个事件附加时间戳
    • Using : 创建与事件源具有相同生命周期的可支配资源
  • 条件操作符:
    评估事件源发出的一个或多个事件源或事件的操作符。
    • All : 确定事件源发出的所有事件是否符合某些条件
    • Amb : 给定两个或多个源事件源,仅从第一个发出事件或通知的事件源中发出所有事件
    • Contains : 确定事件源是否发出指定项目
    • DefaultIfEmpty : 如果源事件源不发出任何内容,则发出默认事件
    • SequenceEqual : 确定两个事件源是否发出相同的事件序列
    • SkipUntil : 丢弃事件源发出的事件,直到第二个事件源发出事件为止
    • SkipWhile : 丢弃事件源发出的事件,直到指定的条件变为false
    • TakeUntil : 在第二个事件源发出事件或终止后,丢弃事件源发出的事件
    • TakeWhile : 在指定条件变为false后丢弃事件源发出的事件
  • 算术操作符:
    对事件源发出的整个事件序列进行算术运算的操作符。
    • Average : 计算事件源发出的数字的平均值并发出此数值
    • Concat : 无交叉的拼接两个或多个事件源发出的事件
    • Count : 计算源事件源发出的事件数并发出此数值
    • Max : 计算事件源发出的数字的最大值并发出此数值
    • Min : 计算事件源发出的数字的最小值并发出此数值
    • Reduce : 相继的用函数处理事件源发出的事件, 并发出最终的值
    • Sum : 计算事件源发出的数字的和并发出此数值
  • 背压(backpressure)操作符:
    • backpressure operators : 当事件源比观察者消耗速度更快的发出事件时的应对策略
  • 连接操作符:
    精确控制的订阅动态的特殊事件源。
    • Connect : 订阅事件源,直到观察者取消订阅
    • Publish : 立即创建事件源的热备份,并将其发出的事件广播到所有订阅者
    • RefCount : 保持事件源的热备份,直到最后一个观察者取消订阅
    • Replay : 立即创建事件源的热备份,并将其发出的事件缓冲并重放给订阅者
  • 转换操作符:
    • To : 将事件源转换为其他类型,例如IEnumerable、IObservable、IObserver等。

常用Linq操作符

  1. Select : 选择集合中的特定字段。

    1
    var names = people.Select(p => p.Name);
  2. Where : 过滤集合中的元素,返回满足条件的元素。

    1
    var adults = people.Where(p => p.Age >= 18);
  3. OrderBy / OrderByDescending : 对集合中的元素进行排序。

    1
    2
    var sortedPeople = people.OrderBy(p => p.Name);   
    var sortedPeopleDesc = people.OrderByDescending(p => p.Age);
  4. GroupBy : 根据某个字段对集合进行分组。

    1
    var groupedByAge = people.GroupBy(p => p.Age);
  5. Join : 连接两个集合,根据某个字段进行匹配。

    1
    2
    3
    4
    5
    6
    7
    var query = from p in people
    join o in orders on p.Id equals o.PersonId
    select new { p.Name, o.OrderAmount };
    ```
    6. Distinct : 返回集合中的不重复元素。
    ```c#
    var uniqueNames = people.Select(p => p.Name).Distinct();
  6. Skip / Take : 跳过/取前n个元素。

    1
    2
    var firstThree = people.Take(3);
    var skipTwo = people.Skip(2).Take(3);
  7. Any : 用于判断集合中是否存在满足条件的元素。

    1
    bool hasAdults = people.Any(p => p.Age >= 18);
  8. All : 用于判断集合中是否所有元素都满足条件。

    1
    bool allAdults = people.All(p => p.Age >= 18);
  9. Count : 用于计算集合中元素的数量。

    1
    int count = people.Count();
  10. Sum / Average / Min / Max :用于计算集合中数值类型元素的总和、平均值、最小值和最大值。

    1
    2
    3
    4
    var totalAge = people.Sum(p => p.Age);
    var averageAge = people.Average(p => p.Age);
    var oldestPersonAge = people.Max(p => p.Age);
    var youngestPersonAge = people.Min(p => p.Age);
  11. First / FirstOrDefault / Last / LastOrDefault :用于获取集合中的第一个或最后一个元素。

    1
    2
    3
    var firstPerson = people.First();
    var firstAdult = people.FirstOrDefault(p => p.Age >= 18);
    var lastPerson = people.Last();
  12. SelectMany : 用于将集合中的元素转换为另一个集合,然后将其展开。

    1
    var allOrders = people.SelectMany(p => p.Orders);
  13. ToList / ToArray : 用于将查询结果转换为列表或数组。

    1
    2
    var peopleList = people.ToList(); 
    var peopleArray = people.ToArray();

Unity中使用ReactiveX

UnityEvent转换为Observable

如果传递了 CancellationToken,则它允许事件源在调用 Cancel 时通过发出 OnCompleted 来调用事件取消订阅。例如,如果您传递了MonoBehaviour.destroyCancellationToken,它将与 GameObject 的生命周期一起可靠地取消订阅。

1
2
3
4
5
public static Observable<Unit> AsObservable(this UnityEngine.Events.UnityEvent unityEvent, CancellationToken cancellationToken = default)
public static Observable<T> AsObservable<T>(this UnityEngine.Events.UnityEvent<T> unityEvent, CancellationToken cancellationToken = default)
public static Observable<(T0 Arg0, T1 Arg1)> AsObservable<T0, T1>(this UnityEngine.Events.UnityEvent<T0, T1> unityEvent, CancellationToken cancellationToken = default)
public static Observable<(T0 Arg0, T1 Arg1, T2 Arg2)> AsObservable<T0, T1, T2>(this UnityEngine.Events.UnityEvent<T0, T1, T2> unityEvent, CancellationToken cancellationToken = default)
public static Observable<(T0 Arg0, T1 Arg1, T2 Arg2, T3 Arg3)> AsObservable<T0, T1, T2, T3>(this UnityEngine.Events.UnityEvent<T0, T1, T2, T3> unityEvent, CancellationToken cancellationToken = default)

UGUI拓展方法

1
2
3
4
5
6
7
8
9
10
11
12
public static IDisposable SubscribeToText(this Observable<string> source, Text text)
public static IDisposable SubscribeToText<T>(this Observable<T> source, Text text)
public static IDisposable SubscribeToText<T>(this Observable<T> source, Text text, Func<T, string> selector)
public static IDisposable SubscribeToInteractable(this Observable<bool> source, Selectable selectable)
public static Observable<Unit> OnClickAsObservable(this Button button)
public static Observable<bool> OnValueChangedAsObservable(this Toggle toggle)
public static Observable<float> OnValueChangedAsObservable(this Scrollbar scrollbar)
public static Observable<Vector2> OnValueChangedAsObservable(this ScrollRect scrollRect)
public static Observable<float> OnValueChangedAsObservable(this Slider slider)
public static Observable<string> OnEndEditAsObservable(this InputField inputField)
public static Observable<string> OnValueChangedAsObservable(this InputField inputField)
public static Observable<int> OnValueChangedAsObservable(this Dropdown dropdown)

可序列化响应式属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class NewBehaviourScript : MonoBehaviour
{
public SerializableReactiveProperty<int> rpInt;
public SerializableReactiveProperty<long> rpLong;
public SerializableReactiveProperty<byte> rpByte;
public SerializableReactiveProperty<float> rpFloat;
public SerializableReactiveProperty<double> rpDouble;
public SerializableReactiveProperty<string> rpString;
public SerializableReactiveProperty<bool> rpBool;
public SerializableReactiveProperty<Vector2> rpVector2;
public SerializableReactiveProperty<Vector2Int> rpVector2Int;
public SerializableReactiveProperty<Vector3> rpVector3;
public SerializableReactiveProperty<Vector3Int> rpVector3Int;
public SerializableReactiveProperty<Vector4> rpVector4;
public SerializableReactiveProperty<Color> rpColor;
public SerializableReactiveProperty<Rect> rpRect;
public SerializableReactiveProperty<Bounds> rpBounds;
public SerializableReactiveProperty<BoundsInt> rpBoundsInt;
public SerializableReactiveProperty<Quaternion> rpQuaternion;
public SerializableReactiveProperty<Matrix4x4> rpMatrix4x4;
public SerializableReactiveProperty<FruitEnum> rpEnum;
public SerializableReactiveProperty<FruitFlagsEnum> rpFlagsEnum;
}

触发器

1
2
3
4
5
6
7
8
9
using R3;
using R3.Triggers;

// when using R3.Triggers, Component or GameObject has [MonoBehaviour Messages]AsObservable extension methods.
this.OnCollisionEnterAsObservable()
.Subscribe(x =>
{
Debug.Log("collision enter");
});

跟踪器(ObservableTracker )

1
2
3
4
5
6
7
8
9
10
11
12
13
ObservableTracker.EnableTracking = true; // default is false
ObservableTracker.EnableStackTrace = true;

using var d = Observable.Interval(TimeSpan.FromSeconds(1))
.Where(x => true)
.Take(10000)
.Subscribe();

// check subscription
ObservableTracker.ForEachActiveTask(x =>
{
Console.WriteLine(x);
});