Reactive programming in Unity with UniRx

Are you looking for alternatives to events and co-routines in Unity? What if Unity would tell you when someone clicked a controller button instead of having to poll for it in the Game loop update? How about being informed every 500ms as long as a button is held? After reading this, you know how to get a stream of button clicks and update a Unity Text by simply increasing a count integer.

In the past I’ve written about how we use reactive programming in Wunderlist. Reactive programming leverages IObservable and IObserver to create and subscribe to streams of data in your app. Not only typical data like lists and tasks can be streamed but also things like timers, keyboard, controller and mouse inputs. Unity3D has its own Rx implementation called UniRx and here is an example of what you can do with it.

shots

Lib in unity

using UnityEngine;
using UnityEngine.UI;

public class App : MonoBehaviour
{
    public Text TextBlock;
}

drag

In the next code, a ReactiveProperty of type int is added for the counter. The reactive property has a method to register to changes to update a UI.Text. In our example, we overload SubscribeToText with a Func that transforms an int into a string with some formatting.

using UniRx;
using UnityEngine;
using UnityEngine.UI;

public class App : MonoBehaviour
{
    public Text TextBlock;

    private ReactiveProperty<int> _counter = new ReactiveProperty<int>();

    private void Start()
    {
        _counter.SubscribeToText(TextBlock, i => $"Shots fired: {i}");
    }
}

Filtering an observable stream

Finally it is time to create an Observable that creates a stream of clicks. UniRx has a function UpdateAsObservable that transforms the Update event to an observable. We start by filtering this stream by checking if the mouse button is down. By this time, we throttle the events to emit every 500 milliseconds and finally subscribe to the observable by calling OnClick. Notice how the value of Reactive Property _counter in the OnClick method is incremented and the UI.Text automatically updates.

using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.UI;

public class App : MonoBehaviour
{
    public Text TextBlock;
    private ReactiveProperty<int> _counter = new ReactiveProperty<int>();

    private void Start()
    {
        this.UpdateAsObservable()
            .Where(_ => Input.GetMouseButton(0))
            .ThrottleFirst(TimeSpan.FromMilliseconds(500))
            .Subscribe(OnClick);

        _counter.SubscribeToText(TextBlock, i => $"Shots fired: {i}");
    }

    private void OnClick(Unit x)
    {
        _counter.Value++;
    }
}

shots