Совсем чуть-чуть про UniRx для Unity

от автора

Примерно год назад я начал работать с этой библиотекой, а теперь настолько к ней привык, что не представляю как без нее можно обходиться. Так как многие знакомые разработчики на Unity совершенно не верят моим восторженным отзывам, здесь я попробую на пальцах показать, как немного улучшить жизнь при работе с ежедневными задачами.

Введение

На Хабре есть два исчерпывающих туториала на тему реактивов в юнити: первая и вторая. Я же попробую ответить на вопрос «зачем, если можно все сделать событиями?»

События

Предположим, у игрока меняется здоровье и мана. А мы их все время показываем в UI.
Очевидный способ — подписка на события изменения этих самых здоровья и маны

public void Init(Player player) {   _player = player;   _player.HealthChanged += SetHealth;   _player.ManaChanged += SetMana; }  public void Dispose() {   _player.HealthChanged += SetHealth;   _player.ManaChanged += SetMana; }

А сам Player будет выглядеть как-то так

public class Player : IPlayer {   private int _health;   private int _mana;    public int Health => _health;   public int Mana => _mana;    public event Action<int> HealthChanged;   public event Action<int> ManaChanged; }

А если мы захотим добавить для игрока интерфейс, то придем к такому варианту

public interface IPlayer {   public int Health { get; }   public int Mana { get; }    public event Action<int> HealthChanged;   public event Action<int> ManaChanged; }

В чем проблема? В том, что при росте данных для показа надо будет каждый раз спускаться до метода Dispose и не забывать отписываться, а также создавать на каждое значение свой метод. Ведь я даже не могу создать n одинаковых вьюшек для показа значений

ReactiveProperty

Чем же поможет в таком случае реактивное поле? Оно позволяет совершать подписку и отписку в одном и том же месте, хотя диспоузом все равно придется воспользоваться.

private List<IDisposable> _disposables = new List<IDisposable>();  public void Init(Player player) {   player.Health     //создаем подписку     .Subscribe(v => { _healthView.text = v.ToString(); })     //добавляем подпику в список очищаемых обьектов     .AddTo(_disposables);   player.Mana.Subscribe(v => { _manaView.text = v.ToString(); }).AddTo(_disposables); }          public void Dispose() {   foreach (var disposable in _disposables)   {     disposable.Dispose();   }   _disposables.Clear(); }

В чем прелесть? В том, что метод Subscribe, которым мы подписываемся на поток, возвращает IDisposable, а значит, мы можем сразу добавлять это в список, который потом будет очищаться. При этом можно не опасаться подписок c помощью лямбд.

Теперь можно глянуть на Player

public class Player : IPlayer {   private ReactiveProperty<int> _health = new();   private ReactiveProperty<int> _mana = new();            public IReadOnlyReactiveProperty<int> Health => _health;   public IReadOnlyReactiveProperty<int> Mana => _mana; }

Так как ReactiveProperty<T> реализует интерфейс IReadOnlyReactiveProperty<T>, мы можем оставлять его торчащим наружу, не опасаясь непрошенных изменений.

ReactiveCollection/ReactiveDictionary

То же самое что и реактивные поля, но здесь надо отдельно подписываться на каждое событие, связанное с коллекцией.

public void Init(IReadOnlyReactiveCollection<Player> players) {   players     //говорим, что хотим отслеживать     .ObserveAdd()     //подписываемся     .Subscribe(v =>      {       //работаем с добавленным элементом       Debug.Log(v.Value);     }).AddTo(_disposables);   players.ObserveRemove().Subscribe(v => { Debug.Log(v.Value); }).AddTo(_disposables);   players.ObserveReplace().Subscribe(v =>   {     Debug.Log(v.OldValue);     Debug.Log(v.NewValue);   }).AddTo(_disposables); }

А как же «все есть поток»?

UniRx позволяет превращать в поток множество вещей: инпут, цикл обновлений юнити, компоненты. А еще пропускать изменения, делать задержки и многие другие вещи (о многих из которых я даже не знаю). Но я хотел показать прелести каждодневного использования, а не увеличить когнитивную нагрузку. Думаю, желающие углубиться могут перейти по прикрепленным на туториалы ссылкам или пойти читать документацию.


ссылка на оригинал статьи https://habr.com/ru/post/717822/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *