Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

UniRx - Reactive Extensions for Unity

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

  1. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    > PresenterBase

    Using PropagateArgument is right, but I've added ForceInitialize to PresenterBase.
    You can touch presenter's property immediately.
    It's just publishing to AssetStore(now under reviwing).
    https://github.com/neuecc/UniRx/releases
    Please wait a moment, ver 4.8.2.

    > AsObservable

    It's only manner:)
    Return IObservable is only upcast, AsObservable() is transform, it's more safety.
    You do not need to do if it is higher cost.
     
  2. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Today, accepted new release "4.8.2" in Asset Store.
    Release note is here.
    ---
    Add : PresenterBase.ForceInitialize
    Improvment : PresenterBase can initialize when inactive in hierarchy
    Improvement : Seperate event triggers into individual classes, thanks@orenro
    Improvement : Separate sources which depend on UnityEngine.dll to UniRx.Library, UniRx.Library.Unity with #UniRxLibrary symbol, thanks@ppcuni
    Fix : WWWErrorException StatusCode for iOS IL2CPP, thanks@DenizPiri
    Fix : ToReactiveProperty doesn't publish value when initial time and value same as defaultValue
    Fix : MainThreadDispatcher thread safety, thanks@pokehanai
    Fix : InspectorDisplayDrawer handles array in object and array of ReactiveProperty
    Breaking Change : Disable ObservableStateMachineBehaviour.OnStateMove, thanks@cruwel
    ---
    UniRx.Library is experimental feature, you can share UniRx both Unity and CLR.
    Its VisualStudio project file is under GitHub's repository, UniRx/Dlls
     
  3. zyzyx

    zyzyx

    Joined:
    Jul 9, 2012
    Posts:
    222
    Hey, great asset!
    Is it possible to do some kind of 2-way databinding with ugui components like toggles or inputfields?
     
  4. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    No, UniRx has only one-way.
    My thoughts of UI with UniRx is here. https://github.com/neuecc/UniRx#model-view-reactivepresenter-pattern
    If you need 2-way databinding, use with other framework(Is it uFrame?)
     
  5. AGeorgy

    AGeorgy

    Joined:
    Sep 16, 2013
    Posts:
    37
    I do:
    Code (CSharp):
    1. return Observable.Range( 0, imagesTest.Count )
    2.            .Do( _ => logger.DebugFormat( "{0}    =>    {1}\n", this, "start GetImage" ) )
    3.            .SelectMany( i => webClient.DownloadFileAsObservable( imagesTest[ i ].Id, AGOSH.Helper.GetFullPath() + "image" + imagesTest[ i ].Id + ".jpg" ) )
    4.            .Do( _ => logger.DebugFormat( "{0}    =>    {1}\n", this, "done GetImage" ) )          
    5.            .Last()
    6.             .Do( _ => logger.DebugFormat( "{0}    =>    {1}\n", this, "done LoadTestImages" ) )
    7.            .AsUnitObservable();
    Result:
    What's wrong? Whyisn't:
    How to do it?
     
  6. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Observable.Range as provider, push value immediately(0,1,2,3,4,5,6...)
    SelectMany + DownloadFile as consumer, it's slow than provider.

    Rx can't control provider's push speed.
    But you can control Observable's concurrency.
    SelectMany doesn't control concurrency(it's parallel), Select + Concat makes sequencial.

    Code (CSharp):
    1. // Before:1~10 immediately, Done:1~10 in sequencial
    2. Observable.Range(1, 10, Scheduler.Immediate)
    3.     .Do(x => Debug.Log("Before:" + x))
    4.     .Select(x => Observable.Timer(TimeSpan.FromSeconds(1)).Select(_ => x))
    5.     .Concat()
    6.     .Do(x => Debug.Log("Done:" + x))
    7.     .Subscribe();
    Concat is same as .Merge(maxConcurrent: 1).
     
  7. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
  8. AGeorgy

    AGeorgy

    Joined:
    Sep 16, 2013
    Posts:
    37
    ок, thanks

    I was confused by this picture:
     
    Last edited: Jul 5, 2015
  9. infine

    infine

    Joined:
    Sep 30, 2013
    Posts:
    7
    Hi there!

    I have a problem with UniRX when I try to build an iOS build with Scripting Backed setting elquals IL2CPP. It says to me "IL2CPP error for type Mono.Security.Protocol.Tls.Handshake.ClientCertificateType". Can you explain this? What can I do to fix it and build my project?
     
  10. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    What version do you use?
    I found Unity's bugs of 5.0.2p1, p2.
    IL2CPP compile error when script contains method group of interface to delegate conversion.
    I already reported it to Unity.

    Simple reproduce program.
    https://gist.github.com/neuecc/1a7c83725b8bb0afa351

    Its bug is maybe not reproduce latest Unity.
    If you use its version, would you upgrade latest Unity and please check it?
     
  11. infine

    infine

    Joined:
    Sep 30, 2013
    Posts:
    7
    Thanks! That worked out for me!
     
  12. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    138
    Hey, I know this is rather OT, but I would like to get gack to question I asked some time ago: best practice for PresenterBase and Model separation. How do you deal with assembly re-loading in such design.

    In your example: CharacterPresenter has a Character model class. I assume Character is regular C# class, so to be able to see it in Inspector the it has to be [Serializable] but in BeforeInitialize() it is new'ed so all the settings from Inspector Edit Mode will be wiped when hitting Play. What is your way of handling this?
     
  13. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    143
    Make Observables visual and more Unity friendly. Also much easier to guys familiar with Unity Events and reuse unity observable/observers function serialization.

    Code (CSharp):
    1. using UnityEngine.Events;
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Reflection;
    5. using UniRx;
    6. using UniRx.InternalUtil;
    7.  
    8.  
    9.  
    10. using UnityEngine;
    11.  
    12. namespace ws.winx.unity{
    13.  
    14.     using UnityEngine.Events;
    15.     using System;
    16.     using System.Collections.Generic;
    17.     using UniRx;
    18.     using UniRx.InternalUtil;
    19.     using UnityEngine;
    20.     using System.Reflection;
    21.  
    22.  
    23.     public static class  ObservableExtensionsEx{
    24.      
    25.      
    26.         public static IDisposable AddListener (this IObservable<GameObject> source,UnityAction call)
    27.         {
    28.          
    29.             return ((UnityObservable)source).Subscribe (call);
    30.          
    31.          
    32.         }
    33.      
    34.         public static IDisposable AddListener<T1> (this IObservable<Tuple<T1,GameObject>> source,UnityAction<T1> call)
    35.         {
    36.          
    37.             return ((UnityObservable<T1>)source).Subscribe (call);
    38.          
    39.         }
    40.      
    41.      
    42.         public static IDisposable AddListener<T1,T2> (this IObservable<Tuple<T1,T2,GameObject>> source,UnityAction<T1,T2> call)
    43.         {
    44.             return ((UnityObservable<T1,T2>)source).Subscribe (call);
    45.         }
    46.      
    47.         public static IDisposable AddListener<T1,T2,T3> (this IObservable<Tuple<T1,T2,T3,GameObject>> source,UnityAction<T1,T2,T3> call)
    48.         {
    49.             return ((UnityObservable<T1,T2,T3>)source).Subscribe (call);
    50.          
    51.         }
    52.      
    53.      
    54.         public static IDisposable AddListener<T1,T2,T3,T4> (this IObservable<Tuple<T1,T2,T3,T4,GameObject>> source,UnityAction<T1,T2,T3,T4> call)
    55.         {
    56.             return ((UnityObservable<T1,T2,T3,T4>)source).Subscribe (call);
    57.          
    58.         }
    59.      
    60.      
    61.     }
    62.  
    63.     [Serializable]
    64.     public class UnityObservable:UnityEvent,IObservable<GameObject>
    65.     {
    66.      
    67.         private Dictionary<UnityAction,IDisposable> __disposables;
    68.         private Subject<GameObject> subject;
    69.         private bool persistentTargetsAreSubscribed;
    70.         private CompositeDisposable __disposer;
    71.      
    72.      
    73.      
    74.      
    75.         //
    76.         // Constructors
    77.         //
    78.         public UnityObservable ():base()
    79.         {
    80.          
    81.             __disposables = new Dictionary<UnityAction, IDisposable> ();
    82.          
    83.             subject = new Subject<GameObject> ();
    84.          
    85.             __disposer = new CompositeDisposable ();
    86.          
    87.             //num of persistent is 0 here, so why SubscibeToPersistent is called in Invoke
    88.         }
    89.      
    90.         public new void AddListener (UnityAction call)
    91.         {
    92.             Subscribe (call);
    93.         }
    94.      
    95.         void SubscibeToPersistent ()
    96.         {
    97.             //check is some listners are subscribed thru editor
    98.             if (!persistentTargetsAreSubscribed && this.GetPersistentEventCount () > 0) {
    99.                 //subscribe persistent obeservers to observer
    100.                 int persistentTargetsNumber = this.GetPersistentEventCount ();
    101.                 MethodInfo methodInfo;
    102.                 UnityEngine.Object persistentTarget;
    103.              
    104.              
    105.              
    106.                 for (int i=0; i<persistentTargetsNumber; i++) {
    107.                  
    108.                     persistentTarget = this.GetPersistentTarget (i);
    109.                     methodInfo = persistentTarget.GetType ().GetMethod (this.GetPersistentMethodName (i));
    110.                     UnityAction call= System.Delegate.CreateDelegate (typeof(UnityAction), persistentTarget, methodInfo) as UnityAction;
    111.                  
    112.                     this.AddListener(call);
    113.                     //subject.Where(trg=>trg==null || trg==(call.Target as MonoBehaviour).gameObject).Subscribe<GameObject> (x => call ())
    114.                  
    115.                 }
    116.              
    117.                 persistentTargetsAreSubscribed = true;
    118.             }
    119.          
    120.          
    121.          
    122.         }
    123.      
    124.         public void InvokeOnTarget (GameObject target)
    125.         {
    126.          
    127.             SubscibeToPersistent ();
    128.          
    129.             if (subject.HasObservers) {
    130.                 subject.OnNext (target);
    131.             }
    132.          
    133.         }
    134.      
    135.         public new void Invoke ()
    136.         {
    137.          
    138.             SubscibeToPersistent ();
    139.          
    140.             if (subject.HasObservers) {
    141.              
    142.                 subject.OnNext(null);
    143.             }
    144.          
    145.         }
    146.      
    147.         public new void RemoveListener (UnityAction call)
    148.         {
    149.             if (__disposables.ContainsKey (call)) {
    150.                 IDisposable disposable=__disposables [call];
    151.                 __disposables.Remove(call);
    152.              
    153.                 disposable.Dispose();
    154.              
    155.                 Debug.Log("Observer "+call.Method.Name+" on target "+call.Target+" Removed");
    156.              
    157.             }
    158.          
    159.          
    160.         }
    161.      
    162.         public new void RemoveAllListeners ()
    163.         {
    164.             foreach (var d in __disposables)
    165.                 d.Value.Dispose ();
    166.          
    167.             __disposables.Clear ();
    168.          
    169.             __disposer.Dispose ();
    170.         }
    171.      
    172.      
    173.      
    174.         public IDisposable Subscribe (UnityAction call)
    175.         {
    176.             IDisposable disposable = subject.Where(tgt=>tgt==null || tgt==(call.Target as MonoBehaviour).gameObject).Subscribe<GameObject> (x => call ());
    177.             __disposables [call] = disposable;
    178.             return disposable;
    179.         }
    180.      
    181.         #region IObservable implementation
    182.         public IDisposable Subscribe (IObserver<GameObject> observer)
    183.         {
    184.             Debug.LogWarning ("Use Subscribe (UnityAction call)");
    185.             return subject.Subscribe<GameObject> (observer.OnNext).AddTo(__disposer);
    186.         }
    187.         #endregion
    188.      
    189.      
    190.      
    191.      
    192.      
    193.      
    194.      
    195.      
    196.     }
    197.  
    198.  
    199.  
    200.     [Serializable]
    201.     public abstract class UnityObservable<T1,T2,T3,T4>:UnityEvent<T1,T2,T3,T4>,IObservable<Tuple<T1,T2,T3,T4,GameObject>>
    202.     {
    203.         private Dictionary<UnityAction<T1,T2,T3,T4>,IDisposable> __disposables;
    204.         private Subject<Tuple<T1,T2,T3,T4,GameObject>> subject;
    205.         private bool persistentTargetsAreSubscribed;
    206.         private CompositeDisposable __disposer;
    207.      
    208.      
    209.      
    210.         //
    211.         // Constructors
    212.         //
    213.         public UnityObservable ():base()
    214.         {
    215.          
    216.             __disposables = new Dictionary<UnityAction<T1,T2,T3,T4>, IDisposable> ();
    217.          
    218.             subject = new Subject<Tuple<T1,T2,T3,T4,GameObject>> ();
    219.          
    220.             __disposer = new CompositeDisposable ();
    221.          
    222.             //num of persistent is 0 here, so why SubscibeToPersistent is called in Invoke
    223.         }
    224.      
    225.         public new void AddListener (UnityAction<T1,T2,T3,T4> call)
    226.         {
    227.             Subscribe (call);
    228.         }
    229.      
    230.      
    231.      
    232.      
    233.         void SubscibeToPersistent ()
    234.         {
    235.             //check is some listners are subscribed thru editor
    236.             if (!persistentTargetsAreSubscribed && this.GetPersistentEventCount () > 0) {
    237.                 //subscribe persistent obeservers to observer
    238.                 int persistentTargetsNumber = this.GetPersistentEventCount ();
    239.                 MethodInfo methodInfo;
    240.                 UnityEngine.Object persistentTarget;
    241.              
    242.              
    243.              
    244.                 for (int i=0; i<persistentTargetsNumber; i++) {
    245.                  
    246.                     persistentTarget = this.GetPersistentTarget (i);
    247.                     methodInfo = persistentTarget.GetType ().GetMethod (this.GetPersistentMethodName (i));
    248.                     UnityAction<T1,T2,T3,T4> call= System.Delegate.CreateDelegate (typeof(UnityAction<T1,T2,T3,T4>), persistentTarget, methodInfo) as UnityAction<T1,T2,T3,T4>;
    249.                  
    250.                     this.AddListener(call);
    251.                     //subject.Where(trg=>trg.Item5==null || trg.Item5==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,T2,T3,T4,GameObject>> (x => call (x.Item1,x.Item2,x.Item3,x.Item4));
    252.                  
    253.                 }
    254.              
    255.                 persistentTargetsAreSubscribed = true;
    256.             }
    257.          
    258.          
    259.          
    260.         }
    261.      
    262.         public void InvokeOnTarget (GameObject target, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
    263.         {
    264.          
    265.             SubscibeToPersistent ();
    266.          
    267.             if (subject.HasObservers) {
    268.                 subject.OnNext (Tuple.Create (arg1, arg2, arg3, arg4, target));
    269.             }
    270.          
    271.         }
    272.      
    273.         public new void Invoke (T1 arg1, T2 arg2, T3 arg3, T4 arg4)
    274.         {
    275.          
    276.             SubscibeToPersistent ();
    277.          
    278.             if (subject.HasObservers) {
    279.              
    280.                 subject.OnNext (Tuple.Create (arg1, arg2, arg3, arg4,(GameObject)null));
    281.             }
    282.          
    283.         }
    284.      
    285.         public new void RemoveListener (UnityAction<T1,T2,T3,T4> call)
    286.         {
    287.             if (__disposables.ContainsKey (call)) {
    288.                 IDisposable disposable=__disposables [call];
    289.                 __disposables.Remove(call);
    290.              
    291.                 disposable.Dispose();
    292.              
    293.                 Debug.Log("Observer "+call.Method.Name+" on target "+call.Target+" Removed");
    294.              
    295.             }
    296.          
    297.          
    298.         }
    299.      
    300.         public new void RemoveAllListeners ()
    301.         {
    302.          
    303.             foreach (var d in __disposables)
    304.                 d.Value.Dispose ();
    305.          
    306.          
    307.             __disposables.Clear ();
    308.          
    309.         }
    310.      
    311.         public IDisposable Subscribe (UnityAction<T1,T2,T3,T4> call)
    312.         {
    313.             //convert UnityAction<T1,T2,T3,T4> to Action<T1,T2,T3,T4>
    314.             IDisposable disposable = subject.Where(tgt=>tgt.Item5==null || tgt.Item5==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,T2,T3,T4,GameObject>> (x => call (x.Item1,x.Item2,x.Item3,x.Item4));
    315.          
    316.             __disposables [call] = disposable;
    317.          
    318.             return disposable;
    319.          
    320.         }
    321.      
    322.      
    323.         #region IObservable implementation
    324.         public IDisposable Subscribe (IObserver<Tuple<T1,T2,T3,T4,GameObject>> observer)
    325.         {
    326.             Debug.LogWarning ("Use Subscribe (UnityAction<T1,T2,T3,T4> call)");
    327.             //Action<Tuple<T1,T2,T3,T4,GameObject>> action = observer.OnNext as Action<Tuple<T1,T2,T3,T4,GameObject>>;
    328.          
    329.          
    330.             //UnityAction<Tuple<T1,T2,T3,T4,GameObject>> call=Delegate.CreateDelegate(typeof(UnityAction<Tuple<T1,T2,T3,T4,GameObject>>),action.Target,action.Method) as UnityAction<Tuple<T1,T2,T3,T4,GameObject>>;
    331.          
    332.             return subject.Subscribe(observer.OnNext).AddTo(__disposer);
    333.         }
    334.         #endregion
    335.      
    336.      
    337.      
    338.      
    339.      
    340.      
    341.      
    342.      
    343.     }
    344.  
    345.     [Serializable]
    346.     public abstract class UnityObservable<T1,T2,T3>:UnityEvent<T1,T2,T3>,IObservable<Tuple<T1,T2,T3,GameObject>>
    347.     {
    348.      
    349.         private Dictionary<UnityAction<T1,T2,T3>,IDisposable> __disposables;
    350.         private Subject<Tuple<T1,T2,T3,GameObject>> subject;
    351.         private bool persistentTargetsAreSubscribed;
    352.         private CompositeDisposable __disposer;
    353.      
    354.      
    355.      
    356.         //
    357.         // Constructors
    358.         //
    359.         public UnityObservable ():base()
    360.         {
    361.          
    362.             __disposables = new Dictionary<UnityAction<T1,T2,T3>, IDisposable> ();
    363.          
    364.             subject = new Subject<Tuple<T1,T2,T3,GameObject>> ();
    365.          
    366.             __disposer=new CompositeDisposable();
    367.          
    368.             //num of persistent is 0 here, so why SubscibeToPersistent is called in Invoke
    369.         }
    370.      
    371.         public new void AddListener (UnityAction<T1,T2,T3> call)
    372.         {
    373.             Subscribe (call);
    374.         }
    375.      
    376.         void SubscibeToPersistent ()
    377.         {
    378.             //check is some listners are subscribed thru editor
    379.             if (!persistentTargetsAreSubscribed && this.GetPersistentEventCount () > 0) {
    380.                 //subscribe persistent obeservers to observer
    381.                 int persistentTargetsNumber = this.GetPersistentEventCount ();
    382.                 MethodInfo methodInfo;
    383.                 UnityEngine.Object persistentTarget;
    384.              
    385.              
    386.              
    387.                 for (int i=0; i<persistentTargetsNumber; i++) {
    388.                  
    389.                     persistentTarget = this.GetPersistentTarget (i);
    390.                     methodInfo = persistentTarget.GetType ().GetMethod (this.GetPersistentMethodName (i));
    391.                     UnityAction<T1,T2,T3> call= System.Delegate.CreateDelegate (typeof(UnityAction<T1,T2,T3>), persistentTarget, methodInfo) as UnityAction<T1,T2,T3>;
    392.                     //subject.Where(trg=>trg.Item4==null || trg.Item4==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,T2,T3,GameObject>> (x => call (x.Item1,x.Item2,x.Item3));
    393.                     AddListener(call);
    394.                 }
    395.              
    396.                 persistentTargetsAreSubscribed = true;
    397.             }
    398.          
    399.          
    400.          
    401.         }
    402.      
    403.         public void InvokeOnTarget (GameObject target, T1 arg1, T2 arg2, T3 arg3)
    404.         {
    405.          
    406.             SubscibeToPersistent ();
    407.          
    408.             if (subject.HasObservers) {
    409.                 subject.OnNext (Tuple.Create (arg1, arg2, arg3, target));
    410.             }
    411.          
    412.         }
    413.      
    414.         public new void Invoke (T1 arg1, T2 arg2, T3 arg3)
    415.         {
    416.          
    417.             SubscibeToPersistent ();
    418.          
    419.             if (subject.HasObservers) {
    420.              
    421.                 subject.OnNext (Tuple.Create (arg1, arg2, arg3, (GameObject)null));
    422.             }
    423.          
    424.         }
    425.      
    426.         public new void RemoveListener (UnityAction<T1,T2,T3> call)
    427.         {
    428.             if (__disposables.ContainsKey (call)) {
    429.                 IDisposable disposable=__disposables [call];
    430.                 __disposables.Remove(call);
    431.              
    432.                 disposable.Dispose();
    433.              
    434.                 Debug.Log("Observer "+call.Method.Name+" on target "+call.Target+" Removed");
    435.              
    436.             }
    437.          
    438.          
    439.         }
    440.      
    441.         public new void RemoveAllListeners ()
    442.         {
    443.          
    444.             foreach (var d in __disposables)
    445.                 d.Value.Dispose ();
    446.          
    447.             __disposables.Clear ();
    448.          
    449.         }
    450.      
    451.         public IDisposable Subscribe (UnityAction<T1,T2,T3> call)
    452.         {
    453.          
    454.             //convert UnityAction<T1,T2,T3> to Action<T1,T2,T3>
    455.             IDisposable disposable = subject.Where(tgt=>tgt.Item4==null || tgt.Item4==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,T2,T3,GameObject>> (x => call (x.Item1,x.Item2,x.Item3));
    456.          
    457.             __disposables [call] = disposable;
    458.          
    459.             return disposable;
    460.          
    461.         }
    462.      
    463.      
    464.         #region IObservable implementation
    465.         public IDisposable Subscribe (IObserver<Tuple<T1,T2,T3,GameObject>> observer)
    466.         {
    467.             Debug.LogWarning ("Use Subscribe (UnityAction<T1,T2,T3> call)");
    468.             return subject.Subscribe<Tuple<T1,T2,T3,GameObject>> (observer.OnNext).AddTo(__disposer);
    469.         }
    470.         #endregion
    471.      
    472.      
    473.      
    474.      
    475.      
    476.      
    477.      
    478.      
    479.     }
    480.  
    481.     [Serializable]
    482.     public abstract class UnityObservable<T1,T2>:UnityEvent<T1,T2>,IObservable<Tuple<T1,T2,GameObject>>
    483.     {
    484.      
    485.      
    486.      
    487.      
    488.         private Dictionary<UnityAction<T1,T2>,IDisposable> __disposables;
    489.      
    490.      
    491.         private Subject<Tuple<T1,T2,GameObject>> subject;
    492.         private bool persistentTargetsAreSubscribed;
    493.         private CompositeDisposable __disposer;
    494.      
    495.      
    496.      
    497.         //
    498.         // Constructors
    499.         //
    500.         public UnityObservable ():base()
    501.         {
    502.          
    503.             __disposables = new Dictionary<UnityAction<T1,T2>, IDisposable> ();
    504.          
    505.             subject = new Subject<Tuple<T1,T2,GameObject>> ();
    506.          
    507.             __disposer = new CompositeDisposable ();
    508.          
    509.             //num of persistent is 0 here, so why SubscibeToPersistent is called in Invoke
    510.         }
    511.      
    512.         public new void AddListener (UnityAction<T1,T2> call)
    513.         {
    514.             Subscribe (call);
    515.         }
    516.      
    517.         void SubscibeToPersistent ()
    518.         {
    519.             //check is some listners are subscribed thru editor
    520.             if (!persistentTargetsAreSubscribed && this.GetPersistentEventCount () > 0) {
    521.                 //subscribe persistent obeservers to observer
    522.                 int persistentTargetsNumber = this.GetPersistentEventCount ();
    523.                 MethodInfo methodInfo;
    524.                 UnityEngine.Object persistentTarget;
    525.              
    526.              
    527.              
    528.                 for (int i=0; i<persistentTargetsNumber; i++) {
    529.                  
    530.                     persistentTarget = this.GetPersistentTarget (i);
    531.                     methodInfo = persistentTarget.GetType ().GetMethod (this.GetPersistentMethodName (i));
    532.                     UnityAction<T1,T2> call= System.Delegate.CreateDelegate (typeof(UnityAction<T1,T2>), persistentTarget, methodInfo) as UnityAction<T1,T2>;
    533.                     //subject.Where(trg=>trg.Item3==null || trg.Item3==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,T2,GameObject>> (x => call (x.Item1,x.Item2));
    534.                     AddListener(call);
    535.                 }
    536.              
    537.                 persistentTargetsAreSubscribed = true;
    538.             }
    539.          
    540.          
    541.          
    542.         }
    543.      
    544.         public void InvokeOnTarget (GameObject target, T1 arg1, T2 arg2)
    545.         {
    546.          
    547.             SubscibeToPersistent ();
    548.          
    549.             if (subject.HasObservers) {
    550.                 subject.OnNext (Tuple.Create (arg1, arg2, target));
    551.             }
    552.          
    553.         }
    554.      
    555.         public new void Invoke (T1 arg1, T2 arg2)
    556.         {
    557.          
    558.             SubscibeToPersistent ();
    559.          
    560.             if (subject.HasObservers) {
    561.              
    562.                 subject.OnNext (Tuple.Create (arg1, arg2, (GameObject)null));
    563.             }
    564.          
    565.         }
    566.      
    567.         public new void RemoveListener (UnityAction<T1,T2> call)
    568.         {
    569.             if (__disposables.ContainsKey (call)) {
    570.                 IDisposable disposable=__disposables [call];
    571.                 __disposables.Remove(call);
    572.              
    573.                 disposable.Dispose();
    574.              
    575.                 Debug.Log("Observer "+call.Method.Name+" on target "+call.Target+" Removed");
    576.              
    577.             }
    578.          
    579.          
    580.         }
    581.      
    582.         public new void RemoveAllListeners ()
    583.         {
    584.          
    585.             foreach (var d in __disposables)
    586.                 d.Value.Dispose ();
    587.          
    588.             __disposables.Clear ();
    589.          
    590.             __disposer.Dispose ();
    591.          
    592.         }
    593.      
    594.         public IDisposable Subscribe (UnityAction<T1,T2> call)
    595.         {
    596.          
    597.             IDisposable disposable= subject.Where(tgt=>tgt.Item3==null || tgt.Item3==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,T2,GameObject>> (x => call (x.Item1,x.Item2));
    598.          
    599.             __disposables [call] = disposable;
    600.          
    601.             return disposable;
    602.          
    603.         }
    604.      
    605.      
    606.         #region IObservable implementation
    607.         public IDisposable Subscribe (IObserver<Tuple<T1,T2,GameObject>> observer)
    608.         {
    609.             Debug.LogWarning ("Use Subscribe (UnityAction<T1,T2> call)");
    610.             return subject.Subscribe<Tuple<T1,T2,GameObject>> (observer.OnNext).AddTo(__disposer).AddTo(__disposer);
    611.         }
    612.         #endregion
    613.      
    614.      
    615.      
    616.      
    617.      
    618.      
    619.      
    620.      
    621.     }
    622.  
    623.  
    624.  
    625.     [Serializable]
    626.     public abstract class UnityObservable<T1>:UnityEvent<T1>,IObservable<Tuple<T1,GameObject>>
    627.     {
    628.      
    629.      
    630.      
    631.      
    632.         private Dictionary<UnityAction<T1>,IDisposable> __disposables;
    633.      
    634.      
    635.         private Subject<Tuple<T1,GameObject>> subject;
    636.         private bool persistentTargetsAreSubscribed;
    637.      
    638.         private CompositeDisposable __disposer;
    639.      
    640.      
    641.         //
    642.         // Constructors
    643.         //
    644.         public UnityObservable ():base()
    645.         {
    646.          
    647.             __disposables = new Dictionary<UnityAction<T1>, IDisposable> ();
    648.          
    649.             subject = new Subject<Tuple<T1,GameObject>> ();
    650.          
    651.             __disposer = new CompositeDisposable ();
    652.          
    653.             //num of persistent is 0 here, so why SubscibeToPersistent is called in Invoke
    654.         }
    655.      
    656.         public new void AddListener (UnityAction<T1> call)
    657.         {
    658.             Subscribe (call);
    659.         }
    660.      
    661.         void SubscibeToPersistent ()
    662.         {
    663.             //check is some listners are subscribed thru editor
    664.             if (!persistentTargetsAreSubscribed && this.GetPersistentEventCount () > 0) {
    665.                 //subscribe persistent obeservers to observer
    666.                 int persistentTargetsNumber = this.GetPersistentEventCount ();
    667.                 MethodInfo methodInfo;
    668.                 UnityEngine.Object persistentTarget;
    669.              
    670.              
    671.              
    672.                 for (int i=0; i<persistentTargetsNumber; i++) {
    673.                  
    674.                     persistentTarget = this.GetPersistentTarget (i);
    675.                     methodInfo = persistentTarget.GetType ().GetMethod (this.GetPersistentMethodName (i));
    676.                     UnityAction<T1> call= System.Delegate.CreateDelegate (typeof(UnityAction<T1>), persistentTarget, methodInfo) as UnityAction<T1>;
    677.                     //subject.Where(trg=>trg.Item2==null || trg.Item2==(call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,GameObject>> (x => call (x.Item1));
    678.                     AddListener(call);
    679.                 }
    680.              
    681.                 persistentTargetsAreSubscribed = true;
    682.             }
    683.          
    684.          
    685.          
    686.         }
    687.      
    688.         public void InvokeOnTarget (GameObject target, T1 arg1)
    689.         {
    690.          
    691.             SubscibeToPersistent ();
    692.          
    693.             if (subject.HasObservers) {
    694.                 subject.OnNext (Tuple.Create (arg1, target));
    695.             }
    696.          
    697.         }
    698.      
    699.         public new void Invoke (T1 arg1)
    700.         {
    701.          
    702.             SubscibeToPersistent ();
    703.          
    704.             if (subject.HasObservers) {
    705.              
    706.                 subject.OnNext (Tuple.Create (arg1,(GameObject)null));
    707.             }
    708.          
    709.         }
    710.      
    711.         public new void RemoveListener (UnityAction<T1> call)
    712.         {
    713.             if (__disposables.ContainsKey (call)) {
    714.                 IDisposable disposable=__disposables [call];
    715.                 __disposables.Remove(call);
    716.              
    717.                 disposable.Dispose();
    718.              
    719.                 Debug.Log("Observer "+call.Method.Name+" on target "+call.Target+" Removed");
    720.              
    721.             }
    722.          
    723.          
    724.         }
    725.      
    726.         public new void RemoveAllListeners ()
    727.         {
    728.             foreach (var d in __disposables)
    729.                 d.Value.Dispose ();
    730.          
    731.             __disposables.Clear ();
    732.          
    733.             //I hope disposer check if something was manually disposed before
    734.             __disposer.Dispose ();
    735.          
    736.         }
    737.      
    738.         public IDisposable Subscribe (UnityAction<T1> call)
    739.         {
    740.          
    741.             IDisposable disposable = subject.Where (tgt => tgt.Item2 == null || tgt.Item2 == (call.Target as MonoBehaviour).gameObject).Subscribe<Tuple<T1,GameObject>> (x => call (x.Item1));
    742.          
    743.             __disposables[call] = disposable;
    744.          
    745.             return disposable;
    746.          
    747.         }
    748.      
    749.         #region IObservable implementation
    750.         public IDisposable Subscribe (IObserver<Tuple<T1,GameObject>> observer)
    751.         {
    752.             Debug.LogWarning ("Use Subscribe (UnityAction<T1> call)");
    753.             return subject.Subscribe<Tuple<T1,GameObject>> (observer.OnNext).AddTo(__disposer);
    754.         }
    755.         #endregion
    756.      
    757.      
    758.      
    759.      
    760.      
    761.      
    762.      
    763.      
    764.     }
    765.  
    766.  
    767.  
    768.  
    769.  
    770.  
    771.  
    772.  
    773.  
    774.  
    775.  
    776.  
    777. }
    778.  
    779.  
    780.  

     
    Last edited: Oct 19, 2015
  14. giovannicampo

    giovannicampo

    Joined:
    Sep 16, 2015
    Posts:
    5
    Hi, first of all great work! I'm very impatient to try uniRx on my project. I have only one concern. I know that using LINQ and Enumerators in general generates a lot of garbage, especially on mobile devices. Is this still true?
     
  15. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Enumerable is stil true, but Observable is not.
    UniRx(Observable) is push style, pipeline's lifecycle is too long(so not garbage).

    Push base application reduce update loop based handling, only value changed difference.
    It have (sometimes) advantage of a performance.
     
  16. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    143
    MainThreadDispatcher, Loom, Ninja and all alike have same sickness they depend on action queue done on the some GameObject. Some event like inputs from devices, loading resources completed or ISerializationCallbackReceiver events Before and After Serialization happen before Awake is triggered on GameObject holding MainThreadDispatcher.
    ISerializationCallbackReceiver events in EditMode are handled on MainThread but in Play mode are dispatched on any available/free thread from ThreadPool and also handled by many threads( This is still burry for me. You can trigger some event from one thread but that doesn't mean that will be executed on that thread but first free) . If you have handlers code that use Unity stuff
    like GameObject.Find and handler is executed on Main thread, everything would be fine. But what if some handlers from other thread then Main thread catch event and try to handle it=> exception is thrown that GameObject.
    Find is forbidden to be executed outside main thread.
    Question: How can observe ISerializationCallbackReceiver events just from main thread and handle in main thread.
    Thx in advance.
     
  17. Gaviali

    Gaviali

    Joined:
    Jul 24, 2013
    Posts:
    1
    Hello, I have a question about the Zip<T> method. Is it possible top zip on hot observables? What I'm trying to do now is:
    IConnectableObservable a1 = ...
    IConnectableObservable a2 = ..
    IConnectableObservable b = Observable.Zip(a1,a2);
    b.Connect()

    But this won't work because Zip only accepts IObservable
     
  18. mandarin

    mandarin

    Joined:
    Dec 8, 2009
    Posts:
    15
    Hi!

    I have made a test case for learning UniRx, and am wondering about an issue. I have a reactive collection of items and want to add new items and delete existing items. The items are visually represented as UI buttons. I'd like to delete an item when I click on one of the buttons, but I can figure out which item to delete.

    Here's my test file:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using System;
    5. using System.Collections;
    6. using UniRx;
    7. using Mandarin;
    8.  
    9. public class Item {
    10.     public string name;
    11. }
    12.  
    13. public class ListManager : MonoBehaviour {
    14.  
    15.     public GameObject   itemPrefab;
    16.     public Transform    itemParent;
    17.     public Button       btnAdd;
    18.  
    19.     private ReactiveCollection<Item> items = new ReactiveCollection<Item>();
    20.  
    21.     void Start() {
    22.         btnAdd.OnClickAsObservable().Subscribe(OnBtnAdd);
    23.         items.ObserveAdd().Subscribe(OnItemAdded);
    24.     }
    25.  
    26.     private void OnBtnAdd(Unit btnAdd) {
    27.         items.Add(new Item { name = ("Item" + items.Count) });
    28.     }
    29.  
    30.     private void OnItemAdded(CollectionAddEvent<Item> itemAdded) {
    31.         GO.Instantiate(itemPrefab)
    32.             .SetParent(itemParent)
    33.             .SetName(itemAdded.Value.name)
    34.             .GetComponent<UIButton>(btn => {
    35.                 btn.GetLabel().text = itemAdded.Value.name;
    36.             })
    37.             .GetComponent<Button>(btn => {
    38.                 btn.OnClickAsObservable()
    39.                     .Subscribe(OnItemClick);
    40.             });
    41.     }
    42.  
    43.     private void OnItemClick(Unit item) {
    44.         Debug.Log("item "+item);
    45.     }
    46. }
    47.  
    GO is a static class I have made to make it easier for me to work with GameObjects. It uses a fluent interface and has methods for doing all kinds of common GameObjects things.

    How can I get access to the button that dispatched the click event? I can't find any documentation on what the Unit class is, and how I'm supposed to use it. I know I still have some more reading to do.
     
  19. siwar-fourati

    siwar-fourati

    Joined:
    Oct 31, 2014
    Posts:
    1
    Hello, I'm looking for a way to execute several tasks repeatedly on certain days of the week. This is the script I used :

    Code (CSharp):
    1. TimeSpan timeSpan = new TimeSpan (alarm.hours, alarm.minutes, alarm.seconds);
    2.      
    3.         DateTimeOffset startTime = DateTimeOffset.Now;
    4.         int times = alarm.occurences;
    5.             var timer = Observable.Timer (startTime, timeSpan).Take (times).Subscribe (x =>
    6.             {
    7.                Alarm(alarm);
    8.             });
    9.  
    But, this executes the method "Alarm" every day. I could check the day in the method, or I can make a timer foreach day. But, is there a better way to do this?

    Any help is appreciated.
     
  20. vidjo

    vidjo

    Joined:
    Sep 8, 2013
    Posts:
    97
    Hello, I noticed that ReactiveProperty.SetValue() generates garbage. Is it possible to get rid of garbage here? Setting values is waaaay too common of an occurance to generate any garbage.

    Edit: I noticed using .SetValueAndForceNotify() does NOT genrate garbage but doing ReactiveProperty.Value = DOES.
     
    Last edited: Nov 27, 2015
  21. RobGraat

    RobGraat

    Joined:
    Oct 12, 2014
    Posts:
    11
    Only difference between the using the ReactiveProperty Value setter and SetValueAndForceNotify, seems to be that the setter checks for value equality:
    Code (CSharp):
    1. this.value.Equals(value)
    My guess is that checking for equality for value types requires them to be boxed when using Equals(). This generates garbage.

    Check it yourself by attaching the following two components to a game object:
    Code (CSharp):
    1. using UnityEngine;
    2. using UniRx;
    3.  
    4. public class IntSequence : MonoBehaviour
    5. {
    6.     private ReactiveProperty<int> gameObjectSequence = new ReactiveProperty<int>();
    7.  
    8.     void Update()
    9.     {
    10.         this.gameObjectSequence.Value += 1;
    11.     }
    12. }
    Code (CSharp):
    1. using UnityEngine;
    2. using UniRx;
    3.  
    4. public class GameObjectSequence : MonoBehaviour
    5. {
    6.     private ReactiveProperty<GameObject> gameObjectSequence = new ReactiveProperty<GameObject>();
    7.     private GameObject objectA = new GameObject();
    8.     private GameObject objectB = new GameObject();
    9.  
    10.     void Update()
    11.     {
    12.         this.gameObjectSequence.Value = this.gameObjectSequence.Value == objectA ? objectB : objectB;
    13.     }
    14. }
    Only the IntSequence.Update() will generate garbage.
    You can avoid GC by changing the setter of the Value property:
    Code (CSharp):
    1. public T Value
    2. {
    3. [...]
    4.         else
    5.         {
    6.             if (EqualityComparer<T>.Default.Equals(this.value, default(T)) || EqualityComparer<T>.Default.Equals(this.value, value)) // don't use EqualityComparer<T>.Default
    7.             {
    8.                 SetValue(value);
    9.                        
    10.                 if (isDisposed) return;
    11.                 if (publisher != null)
    12.                 {
    13.                     publisher.OnNext(this.value);
    14.                 }
    15.             }
    16.         }
    17.     }
    18. }
    However, note the // don't use EqualityComparer<T>.Default comment from neuecc, which he probably wrote for good reason. But I have no idea why... :)
     
  22. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    I'm sorry to have kept you waiting so long, I was trying re-wrote new version and today released UniRx 5.0.0.
    New version achived 3x~10x performance, clean stacktrace and less gc garbage.



    Stacktrace indicates no overhead, the performance is as you wrote.

    Full release notes is here.

    Breaking Changes:
    iOS/AOT support is dropped. Now supports only IL2CPP on iOS.
    Unit/Tuple/CancellationToken/TimeInterval/Timestamped changed class to struct.
    MainThreadDispatcher.Post needs T state.
    ObservableMonoBehaviour/TypedMonoBehaviour marked Obsolete.
    Remove AotSafe Extensions(WrapValueToClass).
    InputField.OnValueChangeAsObservable renamed to OnValueChangedAsObservable in Unity 5.3.
    Operator's chain acquired unhandled exception durability in Subscribe in Subscribe.

    Add:
    Observable.ForEachAsync
    Observable.Take(duration)
    Observable.Aggregate
    Observable.Zip(T3~T7)
    Observable.CombineLatest(T3~T7)
    Observable.Start(function, timeSpan)
    Observable.ToYieldInstruction in Unity 5.3
    Observable.DoOnError
    Observable.DoOnCompleted
    Observable.DoOnTerminate
    Observable.DoOnSubscribe
    Observable.DoOnCancel
    Observable.CreateSafe
    Progress
    StableCompositeDisposable
    MultilineReactivePropertyAttribute

    Fix:
    Observable.First call onNext many times, thanks @TORISOUP
    Fix ScheduledDisposable will never call disposable's dispose, thanks @yaegaki
    Fix explicitly is UniRx.Diagnostics.Logger, thanks @enpel
    ReplaySubject does not use target scheduler.Now, thanks @CoderMin
    EveryEndOfFrameCore was using WaitForFixedUpdate, thanks @mavriel
    ObservableWWW.Post cause runtime error when externalheaders conflicts, thanks @huminado
    WWWErrorException.ToString can't show string when WWW was disposed
    AsyncSubject, ReplaySubject didn't implement IDisposable

    Improvement:
    Made Parent available to children within PresenterBase, thanks @JimW
    Removed redundant onCompleted on AsyncSubject, thanks @j6lim
    Implement IDisposable for ReactiveDictionary, thanks @lostfictions
    Implement IDisposable for ReactiveCollection
    Cached WaitForFixedUpdate/WaitForEndOfFrame YieldInstrtuction, thanks @qiankanglai
    FromCoroutine in Editor Support Unity 5.3 CustomYieldInstruction
    Optimize yield sequnece if reportProgess == null on AsyncOperation.AsObservable and ObservableWWW
    Add WWWErrorException.Text property
    ThreadPoolScheduler and MainThreadScheduler are reduced garbage in some time-based operations(Timer/Interval/Sample/etc...) by ISchedulerPeriodic
    ObserveOn(MainThreadScheduler) is reduced garbage by ISchedulerQueueing

    ---

    > vidjo, RobGraat

    Thank you for report, main reason is avoid AOT problem.
    But 5.0.0 dropped AOT support, I'll try your sugestion.
     
    zyzyx, BLarentis and movra like this.
  23. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Hi, today I released UniRx 5.1.0

    This release eliminates boxing for performance improvement, thank you @vidjo @RobGraat .

    ReactiveProperty.SetValue, Observable.Distinct, DistinctUntilChanged, ObserveEveryValueChanged was caused boxing.
    I treated there boxing.
    Unity's ValueType(Vector2/Rect/etc...) does not implemented IEquatable[T] so it cause boxing in EqualityComparer[T].Default.
    I've added UnityEqualityComparer.Vector2/Vector3/Vector4/Color/Rect/Bounds/Quaternion and GetDefault[T], it can avoid boxing in Unity's ValueType.
    It is used automatically in ReactiveProperty.SetValue, Observable.Distinct, DistinctUntilChanged, ObserveEveryValueChanged.

    ---

    Add : Observable.EveryLateUpdate
    Add : Observable.EveryAfterUpdate in Unity 5.3
    Add : Observable.EveryGameObjectUpdate
    Add : Observable.ObserveOnMainThread(MainThreadDispatchType.Update/FixedUpdate/EndOfFrame/GameObjectUpdate/LateUpdate/AfterUpdate)
    Add : UnityEqualityComparer.Vector2/Vector3/Vector4/Color/Rect/Bounds/Quaternion and GetDefault[T] for avoid boxing
    Improvement : Support Unity 4.7
    Improvement : ReactiveProperty.SetValue avoids boxing
    Improvement : UniRx.Tuple implements IEquatable[T] for avoid boxing
    Improvement : Observable.Distinct/DistinctUntilChanged/ObserveEveryValueChanged use UnityEqualityComparer for avoid boxing
    Improvement : ReactiveCollection implements IReadOnlyReactiveCollection
    Improvement : ReactiveDictionary implements IReadOnlyReactiveDictionary
    Improvement : MainThreadDispatcher doesn't use Array.Clear

    ---

    I've added new Observable.LateUpdate/EveryAfterUpdate/GameObjectUpdate.
    There execution order is
    EveryGameObjectUpdate(in MainThreadDispatcher's Execution Order) -> EveryUpdate -> EveryAfterUpdate -> EveryLateUpdate -> EveryEndOfFrame
    EveryAfterUpdate is only available in Unity 5.3(it uses small hack of custom coroutine).
    Please see details https://github.com/neuecc/UniRx#framecount-based-time-operators

    // Update:
    Sorry, EveryAfterUpdate does not guranteed after EveryUpdate.
    It is same timing of EveryUpdate, I'll mark Obsolete on next release...
     
    Last edited: Jan 5, 2016
  24. cjmanca

    cjmanca

    Joined:
    Dec 6, 2013
    Posts:
    10
    I'm glad to see you're working on performance and garbage.

    I really like this library, and am really looking forward to it being more efficient!

    Would it be possible to try to avoid Coroutines where it's efficient to do so (especially for EveryUpdate and similar, where there are more efficient ways for these to be called). The IEnumerable in the coroutines are generating garbage each frame.

    Also see:
    http://forum.unity3d.com/threads/c-coroutine-waitforseconds-garbage-collection-tip.224878/
    specifically:
    http://forum.unity3d.com/threads/c-...s-garbage-collection-tip.224878/#post-2436633
     
    Last edited: Jan 10, 2016
  25. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Thank you, nice information.
    Of course already I use cached yield instruction and IEqualityComparer[T].

    An alternative way of EveryUpdate, you can use `Observable.EveryGameObjectUpdate`, it built on GameObject.Update and Subject[T]'s publish action.
    But I recommend use EveryUpdate, Subject is not desgined frequently add/remove.
     
  26. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
  27. yuriki

    yuriki

    Joined:
    Jun 19, 2013
    Posts:
    4
    Hi

    What about WebGL + UniRx? (I'm asking because I can't find other reason why I can't build my Unity project for WebGL)
     
    yuliyF likes this.
  28. yuliyF

    yuliyF

    Joined:
    Nov 15, 2012
    Posts:
    144
    I think a UniRx is generated a many garbage and you can't use it on WebGL or I'm wrong?
     
  29. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Sorry, I can't understand why you can't build, please send build error log.

    Someone use UnIRx on WebGL.
    https://gitter.im/neuecc/UniRx?at=56882ae2653b30761d7702c6

    If occurs runtime error, it comes from ThreadPool support(Unity's WebGL does not support ThreadPool yet).
    But UniRx can replace ThreadPoolScheduler.

    Code (CSharp):
    1. #if WEB_GL
    2.     // Default AsyncConversions is Scheduler.ThreadPool
    3.     Scheduler.DefaultSchedulers.AsyncConversions = Scheduler.MainThread;
    4. #endif
     
  30. puzzlekings

    puzzlekings

    Joined:
    Sep 6, 2012
    Posts:
    385
    Hey @neuecc

    In the latest Unity Asset Store package 5.1 the example scenes from 1-11 are missing :(

    cheers

    N
     
  31. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Ah, sorry, now 1-11 is only script.
    I'll add example scene near future.
     
  32. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Hi, today accepted new release UniRx 5.2.0.

    This release has been changed root directory under Plugins.
    It is for avoid uNET Weaver Error.

    ---

    Add : Observable.Pairwise overload(returns Pair[T])
    Add : Observable.ContinueWith
    Add : Observable.Share
    Add : Observable.ZipLatest
    Add : Observable.WithLatestFrom
    Add : Observable.TakeLast
    Add : Observable.GroupBy
    Add : IObserver.Synchronize
    Add : ISubject.Synchronize
    Add : RangeReactivePropertyAttribute
    Fix : Subscribe() throw exception on OnError (this is degraded from UniRx 5.0)
    Fix : ToAwaitableEnumerator is called callback when canceled
    Fix : Wait complete of WWW when called dispose before completed, it's workaround for freeze bug of Android
    Breaking Changes : Buffer(windowBoundaries), Buffer(timeSpan, count) should publish value when buffer is empty.
    Breaking Changes : UniRx has been moved under Plugins directory for avoid uNET Weaver Error
    Breaking Changes : Obsolete Observable.EveryAfterUpdate
    Breaking Changes : Obsolete MainThreadDispatchType.AfterUpdate
     
    RobGraat and zyzyx like this.
  33. Jimww

    Jimww

    Joined:
    May 14, 2013
    Posts:
    63
    Hi, This is exactly what I'm looking for and thank you for sharing this, but I'm having trouble tracking down the actual code I need to copy from these 1st 2 links, that will allow your gist to compile. They're both returning 404 errors now. I was hoping to find maybe 2 files I could copy and add to my project, but not so easy..

    UPDATE:
    I used the following files from https://github.com/InvertGames/uFrame/tree/1.6/MVVM and it seems to work so far:
    NotifyCollectionChangedAction
    NotifyCollectionChangedEventArgs
    NotifyCollectionChangedEventHandler
    ObservableCollection
     
    Last edited: Feb 28, 2016
  34. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    138
  35. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    You can get from old mono-branch.
    https://github.com/mono/mono/tree/mono-3.12.0-branch/mcs/class/System/System.Collections.ObjectModel
    https://github.com/mono/mono/tree/mono-3.12.0-branch/mcs/class/System/System.Collections.Specialized
     
  36. RobGraat

    RobGraat

    Joined:
    Oct 12, 2014
    Posts:
    11
    Hi,

    Do you have any idea why the type could be inferred in the Where extension method:
    upload_2016-4-1_9-29-7.png
    But not in the Subscribe method while writing the onNext action argument?
    upload_2016-4-1_9-28-0.png
    Once I complete writing a valid onNext action the type is inferred by the compiler:
    upload_2016-4-1_9-32-50.png
    Of course specifying the type works but I would rather avoid doing that everytime I use Subscribe method:
    upload_2016-4-1_9-34-34.png
     
  37. sucineri3

    sucineri3

    Joined:
    Apr 6, 2016
    Posts:
    1
    Hi, Thanks for the great work. I'm new to Reactive Programming and I have a few questions about managing the life time of a stream.

    I have a non-monobehavior class(Foo) owning a Subject. Assuming all subscribers to this Subject will manage their life cycles, do I still need to call onCompleted() when the class is no longer needed? If that's the case, should I be doing it in the destructor of the class? I still have the option to turn this class into a monobehavior but I would love to learn how to handle this in a non-monobehavior case. Thanks!

    Some code samples:
    Code (CSharp):
    1.     public class Foo
    2.     {
    3.         Subject<Unit> stream = new Subject<Unit>();
    4.  
    5.         public IObservable<Unit> GetFooObservable()
    6.         {
    7.             return stream.AsObservable<Unit>();
    8.         }
    9.  
    10.         // Is this necessary?
    11.         ~Foo()
    12.         {
    13.             stream.OnCompleted();
    14.             stream.Dispose();
    15.         }
    16.     }
    17.  
    18.     public class Bar: MonoBehaviour
    19.     {
    20.         public void Init(Foo foo)
    21.         {
    22.             foo.GetFooObservable().Subscribe( x => {
    23.                 // Do something
    24.             }).AddTo(this);
    25.         }
    26.     }
     
  38. LostInTheMachine

    LostInTheMachine

    Joined:
    Aug 8, 2010
    Posts:
    48
    Hi there.

    Thanks so much for putting this out there for free.

    I started with a clean project but for me it's not building at the moment. There are 2 critical compilation errors.

    Couldn't call method UNetDomainReload because the class NetworkIdentity or method couldn't be found.

    Assets/Plugins/UniRx/Scripts/UnityEngineBridge/UnityUIComponentExtensions.cs(97,35): error CS1061: Type `UnityEngine.UI.InputField' does not contain a definition for `onValueChanged' and no extension method `onValueChanged' of type `UnityEngine.UI.InputField' could be found (are you missing a using directive or an assembly reference?)

    Cheers
    S
     
  39. LostInTheMachine

    LostInTheMachine

    Joined:
    Aug 8, 2010
    Posts:
    48
    An update for this. I was running 5.3.2 on OSX and just upgraded. All the errors magically went away.
     
  40. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
    hi,I am thinking to dive into reactive programming, before that I would like to make sure its efficient enough for mobile and use it for most of logic in game.

    also is there any good video tutorials available which we can watch to understand UniRx in more depth? Somehow I am confuse over where to start learning it ? I have gone through some of RxJava stuff but its kind of overhead for beginner
     
  41. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    Subject is an alternative of event, no needs publish OnCompleted.
    So destructor is not necessary on non-monobehaviour class.
     
  42. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    My company uses it for mobile game and I'm reported some mobile games already use UniRx.

    Learning resources of Reactive Programming's concept is RxJava, RxJS, RxSwift's docs...
    But yes, there is no specialized resources of UniRx.

    Here is small document about UniRx? (UniRx Rundown(pdf)).
    https://github.com/InvertGames/uFra...lob/master/pages/home.md#reactive-programming

    This slide is best introduction of UniRx but written in Japanese.
    http://www.slideshare.net/torisoup/unity-unirx
     
    idurvesh likes this.
  43. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
    Thanks for it. Unfortunately can't read Japanese though get good idea from pdf it was nice for beginners ...
     
  44. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
    Hi , I am trying to run this simple code, but its not working

    Code (CSharp):
    1.  
    2.  
    3.         this.OnMouseDownAsObservable()
    4.               .SelectMany(_ => this.UpdateAsObservable())
    5.               .TakeUntil(this.OnMouseUpAsObservable())
    6.               .Select(_ => Input.mousePosition)
    7.               .Subscribe(x => Debug.Log(x));

    I tried using this code in Start() ,Update()

    Added uGUI element and attach the script to it, still its not working....What's I am missing?

    ****Edit***

    Working now.Need to have old GUI or object with collider
     
    Last edited: Apr 15, 2016
  45. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
    @neuecc hi, I am using FloatReactiveProperty and making it
    Code (CSharp):
    1.     myReactiveProperty.ObserveEveryValueChanged(x => x).TakeUntilDisable(this).Subscribe(x=> Debug.Log(x));
    though when I change value from inspector it doent throw Debug msg unlike
    Code (CSharp):
    1. this.transform.ObserveEveryValueChanged(x => x.position).Subscribe(x => Debug.Log(x));
    where I do get debug message....

    If I do
    Code (CSharp):
    1.  Observable.EveryUpdate().Subscribe(Cross_ => myReactiveProperty.ObserveEveryValueChanged(x => x).FirstOrDefault().Subscribe(sbyt => Debug.Log(sbyt)));
    Then also I am getting debug as expected ...Whats case with first query?
     
  46. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    ReactiveProperty does not needs `ObserveEveryValueChanged` beacuse ReactiveProperty is observable.
    You can get debug message

    myReactiveProperty.SubScribe(x => Debug.Log(x));

    myReactiveProperty.Value = 100;
    myReactiveProperty.Value = 200;
    myReactiveProperty.Value = 300;
     
    idurvesh likes this.
  47. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
    Thanks for clarification...COuld you also put spotlight on FromEventPattern and FromEvent ? Its quite confusing on when to use what...

    especially this part from exmple is too complex to understand,
    Code (CSharp):
    1.  // convert to IO<EventPattern> as (sender, eventArgs)
    2.             Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(
    3.                     h => h.Invoke, h => FooBar += h, h => FooBar -= h)
    4.                 .Subscribe()
    5.                 .AddTo(disposables); // IDisposable can add to collection easily by AddTo
    6.  
    7.             // convert to IO<EventArgs>, many situation this is useful than FromEventPattern
    8.             Observable.FromEvent<EventHandler<MyEventArgs>, MyEventArgs>(
    9.                     h => (sender, e) => h(e), h => FooBar += h, h => FooBar -= h)
    10.                 .Subscribe()
    11.                 .AddTo(disposables);
    12.  
    13.             // You can convert Action like event.
    14.             Observable.FromEvent<int>(
    15.                     h => FooFoo += h, h => FooFoo -= h)
    16.                 .Subscribe()
    17.                 .AddTo(disposables);
    18.  
    19.             // AOT Safe EventHandling, use dummy capture, see:https://github.com/neuecc/UniRx/wiki/AOT-Exception-Patterns-and-Hacks
    20.             var capture = 0;
    21.             Observable.FromEventPattern<EventHandler<MyEventArgs>, MyEventArgs>(h =>
    22.                 {
    23.                     capture.GetHashCode(); // dummy for AOT
    24.                     return new EventHandler<MyEventArgs>(h);
    25.                 }, h => FooBar += h, h => FooBar -= h)
    26.                 .Subscribe()
    27.                 .AddTo(disposables);
    What does Fromevent<int> doing there? its only contain += and -= in it.When does FromEvent /FromEventPattern would get call?

    May be simple example of debugging hello world from both FromEvent and FromEventPattern would help me understand it more easily.

    Thank you for your time.Please replay soon.
     
  48. neuecc

    neuecc

    Joined:
    Apr 20, 2014
    Posts:
    108
    FromEvent[int] targets only Action[int], others target all delegates so require conversion.
    But understand mechanism of FromEvent, FromEventPattern is difficult, you needs deep C# knowledge.
     
    idurvesh likes this.
  49. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
  50. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    473
    @neuecc I have been learning some stuff on Rx.net from introtorx.com's book.....In the usage guideline author has mentioned not to use Subject types for performance ..Let me quote it,

    http://www.introtorx.com/content/v1.0.10621.0/18_UsageGuidelines.html

    In our UniRx's example script of event handler I see this comment,
    Isn't both quotes contradicts each other? What's prefer way to subscribe to event?