Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

UniRx - Reactive Extensions for Unity

Discussion in 'Assets and Asset Store' started by neuecc, May 28, 2014.

  1. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    733
    So yeah dumb newbie mistake, and the errors were just no helpful. The problem is I didn't have "async" on the method signature. Adding that fixed it.
     
  2. spvn

    spvn

    Joined:
    Dec 10, 2013
    Posts:
    46
    Can someone help me with a really basic question regarding the code to detect double clicks:

    Code (CSharp):
    1. var clickStream = Observable.EveryUpdate()
    2.                 .Where(_ => Input.GetMouseButtonDown(0));
    3.  
    4.             clickStream.Buffer(clickStream.Throttle(TimeSpan.FromMilliseconds(250)))
    5.                 .Where(xs => xs.Count >= 2)
    6.                 .Subscribe(xs => Debug.Log("DoubleClick Detected! Count:" + xs.Count));
    From what I can tell from documentation here and here, Throttle() propagates only the LAST event once 250ms is up. But the above code only makes sense if Throttle propagates ALL the events until 250ms has passed. Which is the case?

    Also more generally, is there some sort of overall API/documentation for all available functions for UniRx and Rx in general? It's hard to tell exactly what I can do with UniRx apart from the examples provided.
     
    Last edited: Mar 6, 2019
  3. sheepjeffery

    sheepjeffery

    Joined:
    Nov 3, 2016
    Posts:
    2
    need support for unity2019

    Assets\Plugins\UniRx\Scripts\Async\Internal\TaskTracker.cs(116,46): error CS0433: The type 'Action<T1, T2, T3, T4, T5>' exists in both 'Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920' and 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
     
  4. RobGraat

    RobGraat

    Joined:
    Oct 12, 2014
    Posts:
    11
    It determines every 250 ms whether there were 2 or more clicks in the last 250 ms using the Buffer operator.

    This site helped me tremendously visualizing the operators: https://rxmarbles.com/
     
    tik_tikkers likes this.
  5. snarai

    snarai

    Joined:
    May 24, 2017
    Posts:
    1
    I am interested in using a method similar to other Rx implementations of .Throttle(TimeSpan duration) which would fire the first event immediately, and then suppress subsequent events until duration has elapsed. In my case, this is to prevent mashing a Button from firing the same event multiple times.

    The current implementation of Throttle is more like Debounce, in that it waits until the duration has elapsed before firing even the first event, but this causes the UI to seem unresponsive and does not work for me.

    I have seen several other solutions for RxNet, however these require either the Publish(Func) syntax, or use of the Window function, neither of which appear to be implemented in UniRx.

    Are there any plans to support these functions? Alternatively, is there any other way within available UniRx API to achieve what I wish?

    Thanks
     
  6. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    733
    I had a similar use case. In my case I wanted to deal with network events but filter out multiple events if they occurred in a short period of time. I don't know Rx very well so I just ended up doing what seemed to work (.Buffer) but it has the same problem of the first event being delayed so I can't use too high of a value.
     
  7. xpation

    xpation

    Joined:
    Mar 8, 2013
    Posts:
    9
    Is this framework still being developed / maintained? There hasn't been commits to GitHub in a very long time. Is it abandoned now with no plans to update to Unity 2019?
     
    Braza and trojanfoe123 like this.
  8. shanecelis

    shanecelis

    Joined:
    Mar 26, 2014
    Posts:
    10
    `SendItself()` will send as class A because it's implemented in A and is effectively calling `Publish<A>(a)`. You could make it virtual, and override it with the same code in B. Or you could use an extension method that'll Publish with the concrete type like so.

    Code (CSharp):
    1. public static class MessageBrokerExtensions {
    2.   public void SendItself<T>(this T obj) {
    3.     MessageBroker.Default.Publish(obj);
    4.   }
    5. }
    Personally, I wouldn't try to engage in a lot of message object inheritance. You're probably better off treating them as Plain Old Data Objects and no inheritance despite it not being DRY because the broker isn't going to respect any kind of inheritance hierarchy. (You could rewrite it to respect inheritance but that'll alter its performance negatively.) If you `Publish<object>(a)` then you'll only `Receive<object>()` regardless of what the type of 'a' actually is.
     
    Last edited: May 3, 2019
  9. Revolter

    Revolter

    Joined:
    Mar 15, 2014
    Posts:
    151
    Just FYI, disposing a Subject with 7000 subscriptions will allocate 150MB of memory.
    UniRx is using ImmutableList in ListObservers, which creates a copy of the list everytime you subscribe or dispose a single Subscription.
     
    andreiagmu likes this.
  10. MechEthan

    MechEthan

    Joined:
    Mar 23, 2016
    Posts:
    166
    andreiagmu likes this.
  11. Jialiang_Lu

    Jialiang_Lu

    Joined:
    Dec 9, 2018
    Posts:
    2
    Hi everyone,

    I have an object in my scene that I want to move every n ms where n is a ReactiveProperty. Another object moves every n ms where n decreases/increases over time. I feel that Observable.Generate with the timeSelector should be the best way to achieve this. Unfortunately, it's not implemented yet. Does anyone know the best solution for this, either implementing Generate myself from Create or find some other workarounds?

    Thanks!
     
  12. Favo-Yang

    Favo-Yang

    Joined:
    Apr 4, 2011
    Posts:
    411
    How to write a setter for ReactiveProperty?

    I have an energy property and limited to a max value. Without UniRx I can do

    Code (CSharp):
    1. public float energy
    2. {
    3.     get { return _energy; }
    4.     set { _energy = Mathf.Min(value, energyMax); }
    5. }
    6. private float _energy;
    With UniRx, something like this?

    Code (CSharp):
    1. public FloatReactiveProperty energy = new FloatReactiveProperty(
    2.     setter: v => Mathf.min(v, energyMax)
    3. );
     
  13. Ekzalphantoss

    Ekzalphantoss

    Joined:
    Sep 27, 2016
    Posts:
    10
    Hi,
    we updated our project to a newer version of Unity and replaced all our texts with TMPro. We encountered a problem with that the TMP_InputField does not have the option of OnValueChangedAsObservable() unlike the regular InputField. Are there plans to add this functionality in the next update?
     
  14. Tempest74

    Tempest74

    Joined:
    May 17, 2017
    Posts:
    133
    Hey, how can I learn how to use it? every tutorial I found is on javascript. I want to see someone who already used this. I find kind of useless the documentation, I do not understand a word
     
  15. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    81
    Code (CSharp):
    1. /// <summary>Observe onEndEdit(Submit) event.</summary>
    2.     public static IObservable<string> OnEndEditAsObservable(this TMP_InputField _inputField)
    3.     {
    4.         return _inputField.onEndEdit.AsObservable();
    5.     }
     
    andreiagmu likes this.
  16. wechat_os_Qy04Id7iTsPXpB9Y6wRowIy-E

    wechat_os_Qy04Id7iTsPXpB9Y6wRowIy-E

    Joined:
    Oct 14, 2019
    Posts:
    1
    TakeWhile doesn't work as expect.
    I want to make it : when mouse down, stop a stream without any help of another stream.
    so i try to use method TakeWhile, but it seems not to work.
    TakeWhile only works well when the Observable is a List of object ( eg. Range(1,10))

    if there are some other ways to do so?

    Code (CSharp):
    1. public class MyTakeWhile : MonoBehaviour
    2. {
    3.     void Start()
    4.     {
    5.         Observable.EveryUpdate()
    6.             .TakeWhile(_ => Input.GetMouseButtonDown(0))
    7.             .Subscribe(_ => Debug.Log(_ + "Mouse haven't down yet!"), () => Debug.Log("already down!"));
    8.  
    9.         //output : not work as expect
    10.         // already down! (however I didn't press any mouse button,it just outputs as soon as game plays)
    11.         //
    12.  
    13.  
    14.        
    15.        
    16.         var stream = Observable.EveryUpdate()
    17.             .Where(_ => Input.GetMouseButtonDown(0));
    18.  
    19.         IDisposable disposable = null;
    20.         disposable = Observable.EveryUpdate()
    21.             .TakeUntil(stream)
    22.             .Subscribe(_ => Debug.Log(_ + " :Mouse haven't down yet!"),
    23.             () =>
    24.             {
    25.                 Debug.Log("already down!");
    26.                 disposable.Dispose();
    27.             }
    28.             );
    29.  
    30.         //output: work as expect but seems not so convenient
    31.         //0 :Mouse haven't down yet!
    32.         //1 :Mouse haven't down yet!
    33.         //...
    34.         //already down!
    35.  
    36.     }
    37. }
     
  17. Zimb000

    Zimb000

    Joined:
    Nov 23, 2017
    Posts:
    1
    I'm not sure if it is supposed to work nor do I know the intricacies of TMP interactions . But feels a bit strange that as I have a stream observing changes in my InputField and a prefix parameter and combines them into text. With TeshMeshPro the text overlaps strangely, but with normal Text component, it works fine. I'm using normal Subscribe for both. Don't really need a fix for this, but just reporting it. As normal Text works in my case just fine, just using mostly TMP.

    var stream = PlayerNameInputField.onValueChanged.AsObservable().Select(_ => PlayerNameInputField.text)
    .Subscribe(_ => PlayerNameTitleText.text = $"{ LocalizationManager.TitlePlayerNamePrefix} {_}");

    TextMeshPro:
    upload_2020-1-31_15-3-24.png

    Text:
    upload_2020-1-31_15-6-42.png
     
  18. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,340
    On the description is written "GameLoop(every Update, OnCollisionEnter, etc), Sensor(like Kinect, Leap Motion, etc) is all of event."

    I have a sensor that I would like to get data from. Does anyone know how UniRX actually work for this kind of situation. What does the code look like.

    Cheers
     
  19. VacuumBreather

    VacuumBreather

    Joined:
    Oct 30, 2013
    Posts:
    65
    Is there any documentation on the operators
    EveryUpdate, EveryFixedUpdate, EveryEndOfFrame, EveryGameObjectUpdate, EveryLateUpdate, ObserveOnMainThread, NextFrame, IntervalFrame
    TimerFrame, DelayFrame, SampleFrame, ThrottleFrame, ThrottleFirstFrame, TimeoutFrame, DelayFrameSubscription, FrameInterval, FrameTimeInterval, BatchFrame

    That is a bit lacking in the package. Some of these are pretty obvious, some are not obvious at all and they mostly do not have any documentation headers, nor are they explained in the wiki?
     
  20. Revolter

    Revolter

    Joined:
    Mar 15, 2014
    Posts:
    151
    Could you please add an extension for AddressableAssets.Load?
     
  21. Braza

    Braza

    Joined:
    Oct 11, 2013
    Posts:
    95
    TL;DR - how to make late subscribers receive previously emitted messages?

    Anyone knows how I can use Replay with MessageBroker.Publish() ? I guess this should do the trick.

    ----------

    I try to make sure my network-dependent objects initialize after the data arrived.

    Some of my objects get created and Subscribe later than MSGPlayerDataLoaded actually fired thus never proceed to OnPlayerDataLoaded.

       protected virtual void Awake()
    {
    MessageBroker.Default.Receive<BaseMessage>().Where(msg => msg.id == GameController.MSGPlayerDataLoaded).Subscribe(msg => OnPlayerDataLoaded());
    }


    Is it possible to look into the past and grab old events since the creation of MessageBroker?
     
    Last edited: Apr 13, 2020
  22. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    3,853
    I love the style of code, concise, easy to read.
    What are the use cases for making games? The more obvious example would be managing enemy and player damage hiding the mesh and wait for a moment to let particle evaporate before recycling the gameobject. Timed events seem very well suited to this.
    Also how are performances?
    I ran 100k enemies on sample12Scene
    could you help me understand where the hiccup come from?
    upload_2020-5-26_1-31-13.png
    Code (CSharp):
    1. // for uGUI(from 4.6)
    2. #if !(UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5)
    3.  
    4. using System;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7. using System.Collections.Generic;
    8.  
    9. namespace UniRx.Examples
    10. {
    11.     public class Sample12_ReactiveProperty : MonoBehaviour
    12.     {
    13.         // Open Sample12Scene. Set from canvas
    14.         public Button MyButton;
    15.         public Toggle MyToggle;
    16.         public InputField MyInput;
    17.         public Text MyText;
    18.         public Slider MySlider;
    19.  
    20.         // You can monitor/modifie in inspector by SpecializedReactiveProperty
    21.         public IntReactiveProperty IntRxProp = new IntReactiveProperty();
    22.  
    23.         public int enemyCount = 1000;
    24.         List<Enemy> enemy = new  List<Enemy>();
    25.  
    26.         void Start()
    27.         {
    28.             for(int i = 0; i < enemyCount; i++)
    29.             {
    30.                 var e = new Enemy(1000);
    31.                 enemy.Add(e);
    32.                 // UnityEvent as Observable
    33.                 // (shortcut, MyButton.OnClickAsObservable())
    34.  
    35.                 // from RxProp, CurrentHp changing(Button Click) is observable
    36.                 //e.CurrentHp.SubscribeToText(MyText);
    37.                 e.IsDead.Where(isDead => isDead == true)
    38.                     .Subscribe(_ =>
    39.                     {
    40.                         MyToggle.interactable = MyButton.interactable = false;
    41.                     });
    42.                 MyButton.onClick.AsObservable().Subscribe(_ => e.CurrentHp.Value -= 99);
    43.             }
    44.  
    45.             // Toggle, Input etc as Observable(OnValueChangedAsObservable is helper for provide isOn value on subscribe)
    46.             // SubscribeToInteractable is UniRx.UI Extension Method, same as .interactable = x)
    47.             MyToggle.OnValueChangedAsObservable().SubscribeToInteractable(MyButton);
    48.  
    49.             // input shows delay after 1 second
    50.             MyInput.OnValueChangedAsObservable()
    51.                 .Where(x => x != null)
    52.                 .Delay(TimeSpan.FromSeconds(1))
    53.                 .SubscribeToText(MyText); // SubscribeToText is UniRx.UI Extension Method
    54.  
    55.             // converting for human visibility
    56.             MySlider.OnValueChangedAsObservable()
    57.                 .SubscribeToText(MyText, x => Math.Round(x, 2).ToString());
    58.  
    59.             // initial text:)
    60.             IntRxProp.SubscribeToText(MyText);
    61.         }
    62.     }
    63.  
    64.     // Reactive Notification Model
    65.     public class Enemy
    66.     {
    67.         public IReactiveProperty<long> CurrentHp { get; private set; }
    68.  
    69.         public IReadOnlyReactiveProperty<bool> IsDead { get; private set; }
    70.  
    71.         public Enemy(int initialHp)
    72.         {
    73.             // Declarative Property
    74.             CurrentHp = new ReactiveProperty<long>(initialHp);
    75.             IsDead = CurrentHp.Select(x => x <= 0).ToReactiveProperty();
    76.         }
    77.     }
    78. }
    79.  
    80. #endif
     
  23. digimbyte

    digimbyte

    Joined:
    Jun 23, 2012
    Posts:
    40
    I am struggling.
    I have several game objects that need an icon overlay, if the user clicks on the icon, the object needs to react
    so the icon is a Gui Image with a 2D collider, and using the example custom trigger, I do get mouse up/ mouse down
    the issue is, what now? I can't run the code inside mouse up/down as it doesn't have the scope of the main monobehaviour.

    do I use this to return when the mouse was up/down?
    I'm not even sure what this code even does
    Code (CSharp):
    1.         public IObservable<Unit> ObservableClickObservable()
    2.         {
    3.             Debug.Log("Observed");
    4.             return onLongPointerDown ?? (onLongPointerDown = new Subject<Unit>());
    5.         }
    because I'm really only interested in if the object was clicked
    void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
     
  24. joeee19

    joeee19

    Joined:
    Jul 14, 2012
    Posts:
    49
    Hi there.

    Please tell me about the values of OnDragAsObservable and Pairwise () of UniRX because they do not behave as expected.

    Code (CSharp):
    1.  
    2. using UniRx.Triggers;
    3. using UnityEngine.UI;
    4. [SerializeField] private Image swipeArea;
    5. swipeArea.OnDragAsObservable()
    6.     .Select(x => x.position)
    7.     .Pairwise()
    If so, it can be compared well with the previous value,but
    Code (CSharp):
    1.  swipeArea.OnDragAsObservable()
    2.     .Pairwise()
    When you compare the positions of x.Current and .Previous, the same value comes in and you cannot compare.

    Touch input is done from UnityRemote, and the platform is iOS.
    Both Unity and UniRX are the latest version.
    The same phenomenon occurs when the method of .Pairwise is changed to Buffer (2,1).
    Finally, I'm having a problem with Subscribe because I want PointerEventData for x.Current.

    Thank you.
     
    Last edited: Jun 8, 2020
  25. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,503
    Has anyone found a good way to cancel in-flight observables without doing nested subscriptions like switchMap does in rxjs? I'm trying to kick off a coroutine from a mouse click which works fine except I can't cancel a previous running coroutine.

    Code (csharp):
    1.  
    2. Observable.EveryUpdate()
    3.     .Where(_ => Input.GetMouseButtonUp(0))
    4.     .Select(_ => mainCamera.ScreenToWorldPoint(Input.mousePosition))
    5.     .Select(pos => new Vector3(pos.x, pos.y, 0))
    6.     .SelectMany(pos => Observable.FromCoroutine(_ => Move(pos), true))
    7.     .RepeatUntilDestroy(gameObject)
    8.     .Subscribe();
    9.  
     
  26. connectwithub

    connectwithub

    Joined:
    Jan 9, 2020
    Posts:
    3
    How can I switch observable when a subject emits?
     
  27. Asinkrit

    Asinkrit

    Joined:
    Aug 27, 2019
    Posts:
    1
    Hi everyone!
    Please tell me what I'm doing wrong. The task was to unload the prefabs of objects through the resources in the stream. The download is successful, but for some reason during the game there is a heavy load on the rendering and physics. In a normal off-stream load, these parameters are much lower.


    private void RXSpawnObjects(BuilderPathData priorityPathData, BuilderPathData secondaryPathData, ObjectPool objectPool, LoadInterface loadInterface)
    {
    GameObject instant = null;
    InstantiateArguments orguments = new InstantiateArguments();
    orguments.objectPool = objectPool;

    for (int i = 0; i < priorityPathData.GetObjectPath.Length; i++)
    {
    orguments.pathPrefab = priorityPathData.GetObjectPath[i];
    Resources.LoadAsync<GameObject>(priorityPathData.GetObjectPath[i])
    .AsAsyncOperationObservable()
    .Subscribe(x =>
    {
    if (x.asset != null)
    {
    count += 1;
    loadInterface.SetProcentProgress(count / priorityPathData.GetObjectPath.Length * 100);
    instant = x.asset as GameObject;
    ObjectPool.InstantiateObjectPoolObjectWithoutAwake(SetOrguments(instant, orguments), photonID, out photonID);

    if (count == priorityPathData.GetObjectPath.Length)
    {
    isReady = true;

    for (int j = 0; j < secondaryPathData.GetObjectPath.Length; j++)
    {
    orguments.pathPrefab = secondaryPathData.GetObjectPath[j];
    Resources.LoadAsync<GameObject>(secondaryPathData.GetObjectPath[j])
    .AsAsyncOperationObservable()
    .Subscribe(y =>
    {
    if (y.asset != null)
    {
    instant = y.asset as GameObject;
    ObjectPool.InstantiateObjectPoolObjectWithoutAwake(SetOrguments(instant, orguments), photonID, out photonID);
    Debug.Log(instant);
    }
    });
    }
    }
    }
    });
    }
    }

    I apologize for the code I wrote.
    And thanks in advance!
     
unityunity