Learning UniRx: Quick tips to get you up to speed
One of the first things I was introduced to when I joined Mighty Bear Games is UniRx. Being completely new to UniRx and reactive programming, I faced some obstacles when trying to pick it up.
Challenge: The search for learning materials online
The first obstacle was in finding sufficient learning materials online. I was searching specifically for UniRx tutorials and although there were good resources linked to this search term, the results were rather limited.
I eventually realised that UniRx’s GitHub page is a good place to start. It is stated there that UniRx is a re-implementation of the .NET Reactive Extensions, with fixes and the addition of some specific utilities for Unity. This is an important point to note, as it means that even if searching for UniRx resources leads us to dead ends, we can search for .NET Rx for examples. I only realised this later on when I stumbled upon learning materials on Rx and reactive programming in general and found them equally helpful. An example would be this article on Rx.
Challenge: Not enough operators! (and how to solve for that)
When I was ready to start experimenting with UniRx in code, the next obstacle was having limited knowledge of the operators that can be applied to data streams. I have benefitted from Khalid’s detailed explanation of the operators I could use and would like to share some of them here.
This was the first operator I learnt to use and ended up using the most. In Disney Melee Mania, characters have Perks that can be equipped and Perk Slots that unlock at different levels. I had a task to activate the notification on a Perk Slot based on 2 conditions:
- When the character has an unlocked and empty Perk Slot, and
- When there is a Perk that can be equipped
Without UniRx, we might write something like this using Actions:
With UniRx, when we have multiple data streams and want to be notified whenever any of the streams emits, we can use CombineLatest:
Let’s say we have some characters, and that we’ve saved their individual notification status in a dictionary that maps character to notification status. We want to retrieve the notification status of the selected character when:
- The selected character changes, or
- The notification status of the selected character changes
We would need to modify the emitted value from a data stream, and this can be done through the use of the Select operator:
By returning characterNotifications[character] in the Select block, our data stream now emits ReactiveProperty<bool> instead of the character enum. In the logs, we see that the Observer is notified when the selected character is set to Character.B and we are able to log the notification status. However, the Observer is not notified when we set Character.B’s notification status to true. To handle this, we would need to use the Switch operator.
When I first read up on the documentation for the Switch Operator, I found the definition quite confusing:
Convert an Observable that emits Observables into a single Observable that emits the items emitted by the most-recently-emitted of those Observables
It only became clearer after I was guided on how to use it in code. In the example above, after applying the Select operator, our data stream now emits Observables (i.e. ReactiveProperty<bool>) — this would be the Observable that emits Observables. Applying the Switch operator after the Select operator would subscribe to the latest ReactiveProperty<bool> Observable emitted, and emit its latest boolean values. The code snippet below shows how we can add the Switch operator to our code:
As seen in the logs, setting Character.B’s notification status to true now notifies the Observer.
This is the last operator I will cover in this article. I was recommended to use SelectMany when I had a nested subscription in my code. For instance, let’s make the following changes to the ToggleNotification function to add a delay:
What I did initially was to subscribe to the ToggleNotification function in a Do block:
While this may seem to work, notice that the ToggleNotification function is not Observable from the main stream, and the timing of "After ToggleNotification done" may not be what we want. A better way to do this would be to use the SelectMany operator:
The SelectMany operator merges emissions from its source Observable and emits its own Observable, in our case, it emits the Observable returned from ToggleNotification. The subsequent Do block now triggers only after ToggleNotification emits.
I’ve enjoyed reflecting on the learning experience, and revisiting and finding new reactive programming resources for this article. Hopefully, people who encounter similar obstacles when trying to get started with UniRx will find the content here helpful.
If you liked this article, do consider dropping some claps and following Mighty Bear Games on Medium!