Reactive programming in Gamedev. Let's understand the approach on Unity development examples
Tags: unity3d, tutorial, programming, gamedev
Published: 2024-04-09 10:27:54

Hello everyone. Today I would like to touch on such a topic as reactive programming when creating your games on Unity. In this article we will touch upon data streams and data manipulation, as well as the reasons why you should look into reactive programming.

**So here we go.**

## What is reactive programming?

> **Reactive programming** is a particular approach to writing your code that is tied to event and data streams, allowing you to simply synchronize with whatever changes as your code runs.

![Reactive Programming in Unity Games Development](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t3as39i40xwfgt5pu4qa.png)

**Let's consider a simple example of how reactive programming works in contrast to the imperative approach:**

![Understanding Reactive Programming in Unity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kriucvxt7qz4xd3tb70x.png)

As shown in the example above, if we change the value of **<mark>B</mark>** after we have entered **<mark>A = B + C</mark>**, then after the change, the value of **<mark>A</mark>** will also change, although this **will not happen in the imperative approach**. A great example that works reactively is **Excel's basic formulas**, if you change the **value of a cell**, the other cells in which you applied the formula will also change - essentially every cell there is a **Reactive Field**.

**So, let's label why we need the reactive values of the variables:**

* When we need automatic synchronization with the value of a variable;
    
* When we want to update the data display on the fly (for example, when we change a model in MVC, we will automatically substitute the new value into the View);
    
* When we want to catch something only when it changes, rather than checking values manually;
    
* When we need to **filter some things** at reactive reactions (for example LINQ);
    
* When we need to **control observables inside reactive fields**;
    

**It is possible to distinguish the main approaches to writing games in which Reactive Programming will be applied:**

* It is possible to **bridge the paradigms of reactive and imperative programming**. In such a connection, <mark>imperative programs could work on reactive data structures (Mostly Used in MVC)</mark>.
    
* **Object-Oriented Reactive Programming.** Is a combination of an **object-oriented approach** with a **reactive approach**. The most natural way to do this is that instead of methods and fields, objects have ***<mark>reactions</mark>*** <mark>that automatically recalculate values, and other reactions depend on changes in those values</mark>.
    
* **Functional-reactive programming**. Basically works well in a variability bundle (e.g. we tell **<mark>variable B to be 2</mark>** until **<mark>C becomes 3</mark>**, then **<mark>B can behave like A</mark>**).
    

## Asynchronous Streams

> **Reactive programming** is programming with **<mark>asynchronous data streams</mark>**. But you may object - after all, **there is Event Bus** or any other event container, which is inherently an asynchronous data stream too. **<mark>Yes, however Reactivity is similar ideas taken to the absolute</mark>**. Because we can create data streams not only from events, **but anything else you can imagine** - variables, user input, properties, caches, structures, and more. In the same way you can imagine a feed in any social media - you watch a stream and can react to it in any way, filter and delete it.

**And since streams are a very important part of the reactive approach, let's explore what they are:**

![Reactive Streams in Unity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scc9omjk55tkp27ra7mc.png)


**<mark>A stream</mark> is a sequence of events <mark>ordered by time</mark>.** It can **throw three types of data:** a **value** (of a particular type), an **error**, or a **completion signal**. A **completion signal** is propagated when we **stop receiving events** (*for example, the propagator of this event has been destroyed*).

**We capture these events asynchronously** by specifying one function to be called when a **value is thrown**, another for **errors**, and a third to handle the **completion signal**. In some cases, **we can omit the last two and focus on declaring a function to intercept the values**. Listening to a stream is called subscribing. The functions we declare are called **observers**. The **stream** is the object of our observations **(observable)**.

**For Example, let's look at Simple Reactive Field:**

```csharp
private IReactiveField<float> myField = new ReactiveField<float>();

private void DoSomeStaff() {
    var result = myField.OnUpdate(newValue => {
        // Do something with new value
    }).OnError(error => {
        // Do Something with Error
    }).OnComplete(()=> {
        // Do Something on Complete Stream
    });
}
```

## Reactive Data stream processing and filtering in Theory

One huge advantage of the approach is the partitioning, grouping and filtering of events in the stream. Most off-the-shelf Reactive Extensions solutions already include all of this functionality.

**We will, however, look at how this can work as an example of dealing damage to a player:**

![Filtering Events in Unity Reactive Programming](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/on5v4u7cp3hule5s03bd.png)


**And let's immediately convert this into some abstract code:**

```csharp
private IReactiveField<float> myField = new ReactiveField<float>();

private void DoSomeStaff() {
    var observable = myField.OnValueChangedAsObservable();
    observable.Where(x > 0).Subscribe(newValue => {
        // Filtred Value
    });
}
```

**As you can see in the example above, we can filter our values so that we can then use them as we need. Let's visualize this as an MVP solution with a player interface update:**

```csharp
// Player Model
public class PlayerModel {
    // Create Health Reactive Field with 150 points at initialization
    public IReactiveField<long> Health = new ReactiveField<long>(150);
}

// Player UI View
public class PlayerUI : MonoBehaviour {
    [Header("UI Screens")]
    [SerializeField] private Canvas HUDView;
    [SerializeField] private Canvas RestartView;

    [Header("HUD References")]
    [SerializeField] private TextMeshProUGUI HealthBar;

    // Change Health
    public void ChangeHealth(long newHealth) {
        HealthBar.SetText($"{newHealth.ToString("N0")} HP");
    }
    
    // Show Restart Screen
    public void ShowRestartScreen() {
        HUDView.enabled = false;
        RestartView.enabled = true;
    }

    public void ShowHUDScreen() {
        HUDView.enabled = true;
        RestartView.enabled = false;
    }
}

// Player Presenter
public class PlayerPresenter {
    // Our View and Model
    private PlayerModel currentModel;
    private PlayerView currentView;

    // Player Presenter Constructor
    public PlayerPresenter(PlayerView view, PlayerModel model = null){
        currentModel = model ?? new PlayerModel();
        currentView = view;
        BindUpdates();
        
        currentView.ShowHUDScreen();
        currentView.ChangeHealth(currentModel.Health.Value);
    }

    // Bind Our Model Updates
    private void BindUpdates() {
        var observable = currentModel.Health.OnValueChangedAsObservable();
        // When Health > 0
        observable.Where(x > 0).Subscribe(newValue => {
            currentView.ChangeHealth(newValue);
        });
        // When Health <= 0
        observable.Where(x <= 0).Subscribe(newValue => {
            // We Are Dead
            RestartGame();
        });
    }
    
    // Take Health Effect
    public void TakeHealthEffect(int amount) {
        // Update Our Reactive Field
        currentModel.Health.Value += amount;
    }

    private void RestartGame() {
        currentView.ShowRestartScreen();
    }
}
```

## Reactive Programming in Unity

You can certainly use both r**eady-made libraries** to get started with the reactive approach and write your own solutions. However, I recommend to take a look at a popular solution proven over the years - [UniRX](https://github.com/neuecc/UniRx).

> **UniRx (Reactive Extensions for Unity)** is a reimplementation of the .NET Reactive Extensions. The Official Rx implementation is great but doesn't work on Unity and has issues with iOS IL2CPP compatibility. This library fixes those issues and adds some specific utilities for Unity. Supported platforms are PC/Mac/Android/iOS/WebGL/WindowsStore/etc and the library.

So, you **can see that the UniRX implementation is similar** to the abstract code we saw earlier. If you have ever worked with **LINQ - it will be easy enough for you to understand the syntax:**

```csharp
var clickStream = Observable.EveryUpdate()
    .Where(_ => Input.GetMouseButtonDown(0));

clickStream.Buffer(clickStream.Throttle(TimeSpan.FromMilliseconds(250)))
    .Where(xs => xs.Count >= 2)
    .Subscribe(xs => Debug.Log("DoubleClick Detected! Count:" + xs.Count));
```

## In conclusion

So, I hope my article helped you a little bit to understand what reactive programming is and why you need it. In game development it can help you a lot to make your life easier.

**I will be glad to receive your comments and remarks. Thanks for reading!**

---

[**My Discord**](https://discord.gg/a7cHDtfYbv) | [**My Blog**](https://devsdaddy.hashnode.dev/) | [**My GitHub**](https://github.com/DevsDaddy) | [**Buy me a Beer**](https://boosty.to/devsdaddy)