Summary of getting started with UniRx in Unity

What is UniRx?

  UniRx is the Unity version of Reactive Extensions. Reactive Extensions in Chinese means: Responsive Extensions. Reactive refers to observers and timers. Extensions refer to LINQ operators. Reactive Extensions is famous for its asynchronous logic and minimalist API style.

Why use UniRx?

  Because many logical operations on the project need to be processed asynchronously in time, there are often more asynchronous logics that need to be implemented. This is why there is the concept of Ctrip.
  In the project, such as animation playback, network request, resource loading, scene transition, etc. are logics that operate asynchronously in time. When we implement the above functional modules on the project, we often use a large number of callbacks to implement, which may cause The project is filled with a large number of callbacks to handle some logic. A relatively good method is to implement practical messages/events, but the result may also lead to a large number of events in the project. After a period of time, you may not understand the logic you wrote. .
  The emergence of UniRx just solved this problem, it is between callbacks and events.

  • It has the concept of events, but its events are like flowing water. We need to organize, transform, filter, merge and other operations on these events during the development process
  • It also uses callbacks, but its callbacks only need to be called once to process the event after the event is organized

Common APIs

Timing function

In ordinary projects, it may often be encountered that some logical operations are triggered after a period of time.
It is usually possible to use coroutines

 void Start()
    {
    
    
        StartCoroutine(Timer(10, DoSomething));
    }
    
    IEnumerator Timer(float seconds,Action callback)
    {
    
    
        yield return new WaitForSeconds(seconds);
        callback();
    }

         
    void DoSomething()
    {
    
    
        Debug.Log("TODO");
    }

The code statement implements the same function as above, after 10s to print, the code is not very clear.

 void Start()
    {
    
    
        Observable
            .Timer(TimeSpan.FromSeconds(10))
            .Subscribe(e => {
    
    
                Debug.Log("DoSomething");
            });
    }

  Another thing to note is that the above writing method is not bound to the life cycle of MonoBehaviour in Unity. Maybe after the MonoBehaviour is destroyed, the logic is still executing, which may cause a null pointer. It needs to be added at the end .AddTo(this). When the life cycle is destroyed, the script logic will also be destroyed. This is also the point that we usually need to pay attention to when writing logic.
code show as below

 void Start()
    {
    
    
        Observable
            .Timer(TimeSpan.FromSeconds(10))
            .Subscribe(e => {
    
    
                Debug.Log("DoSomething");
            })
            .AddTo(this);
    }

Update

  When writing a functional module, some logic may be defined in Update, and the amount of code in Update may be large with the project. With UniRx you can keep your code independent of each other. As follows: ( 注意不要忘记在最后添加.AddTo(this))

void Start()
    {
    
    
        Observable
            .EveryUpdate()
            .Subscribe(e => {
    
    
                Debug.Log("QQQ");
            })
            .AddTo(this);

        Observable
           .EveryUpdate()
           .Subscribe(e => {
    
    
               Debug.Log("WWW");
           })
           .AddTo(this);

        Observable
           .EveryUpdate()
           .Subscribe(e => {
    
    
               Debug.Log("EEE");
           })
           .AddTo(this);
    }

The above code can be defined separately through the division of business modules in actual projects, which is also convenient for future maintenance.

operatorFirst

In ordinary projects, you may also encounter related functions that need to be executed for the first time but not later. For conventional implementation, we may define a bool value and assign it to false after execution once. Take the first mouse click as an example. The key word is First. code show as below

  void Start()
    {
    
    
        Observable
            .EveryUpdate()
            .First(_=>Input.GetMouseButtonDown(0))
            .Subscribe(e => {
    
    
                Debug.Log("EEE");
            })
           .AddTo(this);
    }

operatorWhere

This Where can be understood as that it can only be executed when certain conditions are met. The code is as follows, print output when the left mouse button is pressed.

void Start()
{
    
    
	 Observable
            .EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(0))
            .Subscribe( _=>
            {
    
    
                Debug.Log("DOSomething");
            })
            .AddTo(this);
}

ReactiveProperty

  ReactiveProperty is the meaning of responsive properties. As the name implies, when assigning a value to a property in the project, it will dynamically execute the relevant logic and directly upload the code. What are the limitations of the following code? When the value changes, the corresponding method can only be performed inside the property Response, what if I want to make a call externally? That may require defining a delegate for binding. UniRx has a more concise API;
conventional writing

 	private int age;
    public int Age
    {
    
    
        get
        {
    
    
            return age;
        }

        set {
    
    
            if (value>0)
            {
    
    
                age = value;
                OnAgeChanged();

            }
        }
    }

    void OnAgeChanged()
    {
    
    
    }

UniRx usage

	public ReactiveProperty<int> Age = new ReactiveProperty<int>();
    void Start()
    {
    
    
        Age.Subscribe(age =>
        {
    
    
            Debug.Log("赋值之后改变的方法");
        });

        Age.Value = 22;
        }

Support for UGUI

You can use UniRx to dynamically bind UI controls, and you can query other usages by yourself. Operators such as Where, , etc. can also be added during definition according to business requirements .First

 public Button btn;
    public Toggle toggle;


    void Start()
    {
    
    
        btn.OnClickAsObservable()
            .Subscribe(_ =>
            {
    
    
                Debug.Log("BtnClick");
            });

        toggle.OnValueChangedAsObservable()
            .Subscribe(isOn =>
            {
    
    
                if (isOn)
                {
    
    

                }
                else
                {
    
     }

            });
            }

Operator Merge

What is introduced here is to merge the stream logic defined by UniRx. The code is as follows: The code defines two event streams, which are merged by the operator Merge. When the left or right mouse button is pressed, it will be printed out.

 void Start()
    {
    
    
        //定义流1
        var stream01 = Observable
            .EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(0));
        //定义流2
        var stream02 = Observable
            .EveryUpdate()
            .Where(_ => Input.GetMouseButtonDown(1));

        Observable.Merge(stream01, stream02)
            .Subscribe(_ => {
    
    
                Debug.Log("DoSomeThing");
            })
            .AddTo(this);
     }

The basic usage is introduced here.

Guess you like

Origin blog.csdn.net/weixin_44446603/article/details/125963100