facebook twitter hatena line email

「Unity/UniRx/値変更検知/ObserveEveryValueChanged配列」の版間の差分

提供: 初心者エンジニアの簡易メモ
移動: 案内検索
(EveryUpdateを使った配列内のデータを検知(代替))
(2度目以降、Observable.Createを実行してくれない場合)
 
(同じ利用者による、間の16版が非表示)
行1: 行1:
 +
==試したこと==
 +
* ObserveEveryValueChangedを配列で検知できる?→NG
 +
* 配列内の値変更を検知するObserveEveryValueChangedを、Observable.Createで作成→OK
 +
* Subjectを使った配列内のキーを検知→OK
 +
* EveryUpdateを使った配列内のデータを検知→NG
 +
 
==ObserveEveryValueChangedを配列で検知できる?==
 
==ObserveEveryValueChangedを配列で検知できる?==
ObserveEveryValueChangedを配列の値変更をできなかった。
+
ObserveEveryValueChangedに配列をそのまま入れるだけだと、値変更を検知できなかった。
 +
 
 +
==配列内の値変更を検知するObserveEveryValueChangedを、Observable.Createで作成==
 +
配列内のIsCompletedがtrueになったらイベント発生するように。
 +
<pre>
 +
using System.Collections;
 +
using System.Collections.Generic;
 +
using UnityEngine;
 +
using UniRx;
 +
using System;
 +
 
 +
public class ChangeValueListObservableScene : MonoBehaviour
 +
{
 +
    class RequestData
 +
    {
 +
        public string Url;
 +
        public bool IsCompleted;
 +
    }
 +
    class SampleClient
 +
    {
 +
        IObservable<int> isCompletedsAsObservable;
 +
        public IObservable<int> IsCompletedsAsObservable { get => isCompletedsAsObservable; set => isCompletedsAsObservable = value; }
 +
        List<RequestData> requestDatas;
 +
        public List<RequestData> RequestDatas { get => requestDatas; set => requestDatas = value; }
 +
        public SampleClient()
 +
        {
 +
            requestDatas = new List<RequestData>();
 +
            requestDatas.Add(new RequestData
 +
            {
 +
                Url = "ttp://example.com",
 +
                IsCompleted = false,
 +
            });
 +
            requestDatas.Add(new RequestData
 +
            {
 +
                Url = "ttp://example2.com",
 +
                IsCompleted = false,
 +
            });
 +
            isCompletedsAsObservable = Observable.Create<int>(observer =>
 +
            {
 +
                int i = 0;
 +
                foreach (RequestData requestData in requestDatas)
 +
                {
 +
                    int id = i;
 +
                    requestData.ObserveEveryValueChanged(_ => _.IsCompleted)
 +
                        .Subscribe(isCompleted =>
 +
                        {
 +
                            observer.OnNext(id);
 +
                        });
 +
                    i++;
 +
                }
 +
                return Disposable.Empty;
 +
            });
 +
        }
 +
        public void Response(int id)
 +
        {
 +
            requestDatas[id].IsCompleted = true;
 +
        }
 +
    }
 +
    void Start()
 +
    {
 +
        int id = 1;
 +
        var sampleClient = new SampleClient();
 +
        sampleClient.IsCompletedsAsObservable
 +
            .Subscribe(id => {
 +
                if (!sampleClient.RequestDatas[id].IsCompleted) return;
 +
                Debug.Log("Id=" + id + " Url=" + sampleClient.RequestDatas[id].Url + " IsCompleted=" + sampleClient.RequestDatas[id].IsCompleted);
 +
            })
 +
            .AddTo(gameObject);
 +
        // 5秒後に遅延実行
 +
        Observable.Timer(System.TimeSpan.FromSeconds(5))
 +
            .Subscribe(_ => {
 +
                sampleClient.Response(id);
 +
            }).AddTo(gameObject);
 +
    }
 +
}
 +
</pre>
 +
参考:http://wp.nonip.net/archives/2740
 +
 
 +
===2度目以降、Observable.Create<int>を実行してくれない場合===
 +
<pre>
 +
IObservable<int> isCompletedsAsObservable;
 +
isCompletedsAsObservable = Observable.Create<int>(observer =>
 +
{
 +
int i = 0;
 +
foreach (RequestData requestData in requestDatas)
 +
{
 +
int id = i;
 +
requestData.ObserveEveryValueChanged(_ => _.IsCompleted)
 +
.Subscribe(isCompleted =>
 +
{
 +
observer.OnNext(id);
 +
});
 +
i++;
 +
}
 +
return Disposable.Empty;
 +
});
 +
</pre>
 +
の部分を
 +
<pre>
 +
Subject<int> isCompletedsAsObservable;
 +
isCompletedsAsObservable = new Subject<int>();
 +
int i = 0;
 +
foreach (RequestData requestData in requestDatas)
 +
{
 +
    int id = i;
 +
    requestData.ObserveEveryValueChanged(_ => _.IsCompleted)
 +
        .Subscribe(isCompleted =>
 +
{
 +
isCompletedsAsObservable.OnNext(id);
 +
});
 +
    i++;
 +
}
 +
</pre>
 +
な感じで置き換えればよい。
 +
 
 +
isCompletedsAsObservable.OnNext(id);の部分が実行されないときは、
 +
isCompletedsAsObservable.Subscribe()が、OnNextより先に定義されてるか確認する。
  
==Subjectを使った配列内のデータを検知(代替)==
+
==Subjectを使った配列内のキーを検知==
 
<pre>
 
<pre>
 
using System.Collections;
 
using System.Collections;
行23: 行145:
 
             isCompletedsAsObservable = new Subject<int>();
 
             isCompletedsAsObservable = new Subject<int>();
 
         }
 
         }
         public void Request(int id)
+
         public void Response(int id)
 
         {
 
         {
 
             isCompletedsAsObservable.OnNext(id);
 
             isCompletedsAsObservable.OnNext(id);
行41: 行163:
 
         Observable.Timer(System.TimeSpan.FromSeconds(5))
 
         Observable.Timer(System.TimeSpan.FromSeconds(5))
 
             .Subscribe(_ => {
 
             .Subscribe(_ => {
                 sampleClient.Request(id);
+
                 sampleClient.Response(id);
 
             }).AddTo(gameObject);
 
             }).AddTo(gameObject);
 
     }
 
     }
行47: 行169:
 
</pre>
 
</pre>
  
==EveryUpdateを使った配列内のデータを検知(代替)==
+
==EveryUpdateを使った配列内のデータを検知==
 
毎フレームごとに処理されるので危険かも。
 
毎フレームごとに処理されるので危険かも。
 
<pre>
 
<pre>
行63: 行185:
 
             IsCompleteds.Add(false);
 
             IsCompleteds.Add(false);
 
         }
 
         }
         public void Request(int id)
+
         public void Response(int id)
 
         {
 
         {
 
             IsCompleteds[id] = true;
 
             IsCompleteds[id] = true;
行89: 行211:
 
         Observable.Timer(System.TimeSpan.FromSeconds(5))
 
         Observable.Timer(System.TimeSpan.FromSeconds(5))
 
             .Subscribe(_ => {
 
             .Subscribe(_ => {
                 sampleClient.Request(id);
+
                 sampleClient.Response(id);
 
             }).AddTo(gameObject);
 
             }).AddTo(gameObject);
 
     }
 
     }
 
}
 
}
 
</pre>
 
</pre>

2023年8月26日 (土) 09:43時点における最新版

試したこと

  • ObserveEveryValueChangedを配列で検知できる?→NG
  • 配列内の値変更を検知するObserveEveryValueChangedを、Observable.Createで作成→OK
  • Subjectを使った配列内のキーを検知→OK
  • EveryUpdateを使った配列内のデータを検知→NG

ObserveEveryValueChangedを配列で検知できる?

ObserveEveryValueChangedに配列をそのまま入れるだけだと、値変更を検知できなかった。

配列内の値変更を検知するObserveEveryValueChangedを、Observable.Createで作成

配列内のIsCompletedがtrueになったらイベント発生するように。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using System;

public class ChangeValueListObservableScene : MonoBehaviour
{
    class RequestData
    {
        public string Url;
        public bool IsCompleted;
    }
    class SampleClient
    {
        IObservable<int> isCompletedsAsObservable;
        public IObservable<int> IsCompletedsAsObservable { get => isCompletedsAsObservable; set => isCompletedsAsObservable = value; }
        List<RequestData> requestDatas;
        public List<RequestData> RequestDatas { get => requestDatas; set => requestDatas = value; }
        public SampleClient()
        {
            requestDatas = new List<RequestData>();
            requestDatas.Add(new RequestData
            {
                Url = "ttp://example.com",
                IsCompleted = false,
            });
            requestDatas.Add(new RequestData
            {
                Url = "ttp://example2.com",
                IsCompleted = false,
            });
            isCompletedsAsObservable = Observable.Create<int>(observer =>
            {
                int i = 0;
                foreach (RequestData requestData in requestDatas)
                {
                    int id = i;
                    requestData.ObserveEveryValueChanged(_ => _.IsCompleted)
                        .Subscribe(isCompleted =>
                        {
                            observer.OnNext(id);
                        });
                    i++;
                }
                return Disposable.Empty;
            });
        }
        public void Response(int id)
        {
            requestDatas[id].IsCompleted = true;
        }
    }
    void Start()
    {
        int id = 1;
        var sampleClient = new SampleClient();
        sampleClient.IsCompletedsAsObservable
            .Subscribe(id => {
                if (!sampleClient.RequestDatas[id].IsCompleted) return;
                Debug.Log("Id=" + id + " Url=" + sampleClient.RequestDatas[id].Url + " IsCompleted=" + sampleClient.RequestDatas[id].IsCompleted);
            })
            .AddTo(gameObject);
        // 5秒後に遅延実行
        Observable.Timer(System.TimeSpan.FromSeconds(5))
            .Subscribe(_ => {
                sampleClient.Response(id);
            }).AddTo(gameObject);
    }
}

参考:http://wp.nonip.net/archives/2740

2度目以降、Observable.Create<int>を実行してくれない場合

IObservable<int> isCompletedsAsObservable;
isCompletedsAsObservable = Observable.Create<int>(observer =>
{
	int i = 0;
	foreach (RequestData requestData in requestDatas)
	{
		int id = i;
		requestData.ObserveEveryValueChanged(_ => _.IsCompleted)
			.Subscribe(isCompleted =>
			{
				observer.OnNext(id);
			});
		i++;
	}
	return Disposable.Empty;
});

の部分を

Subject<int> isCompletedsAsObservable;
isCompletedsAsObservable = new Subject<int>();
int i = 0;
foreach (RequestData requestData in requestDatas)
{
    int id = i;
    requestData.ObserveEveryValueChanged(_ => _.IsCompleted)
        .Subscribe(isCompleted =>
		{
			isCompletedsAsObservable.OnNext(id);
		});
    i++;
}

な感じで置き換えればよい。

isCompletedsAsObservable.OnNext(id);の部分が実行されないときは、 isCompletedsAsObservable.Subscribe()が、OnNextより先に定義されてるか確認する。

Subjectを使った配列内のキーを検知

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using System;

public class ChangeValueListSubjectScene : MonoBehaviour
{
    class SampleClient
    {
        public List<string> Urls = new List<string>();
        Subject<int> isCompletedsAsObservable;
        public IObservable<int> IsCompletedsAsObservable { get => isCompletedsAsObservable; }
        public SampleClient()
        {
            Urls.Add("ttp://example.com");
            Urls.Add("ttp://example2.com");
            isCompletedsAsObservable = new Subject<int>();
        }
        public void Response(int id)
        {
            isCompletedsAsObservable.OnNext(id);
        }
    }
    void Start()
    {
        int id = 1;
        var sampleClient = new SampleClient();
        sampleClient.IsCompletedsAsObservable
            .Subscribe(id => {
                Debug.Log("Id=" + id + " sampleClient.Url=" + sampleClient.Urls[id]);
            })
            .AddTo(gameObject);

        // 5秒後に遅延実行
        Observable.Timer(System.TimeSpan.FromSeconds(5))
            .Subscribe(_ => {
                sampleClient.Response(id);
            }).AddTo(gameObject);
    }
}

EveryUpdateを使った配列内のデータを検知

毎フレームごとに処理されるので危険かも。

public class ChangeValueListScene : MonoBehaviour
{
    class SampleClient
    {
        public List<string> Urls = new List<string>();
        public List<bool> IsCompleteds = new List<bool>();
        public SampleClient()
        {
            Urls.Add("ttp://example.com");
            Urls.Add("ttp://example2.com");
            IsCompleteds.Add(false);
            IsCompleteds.Add(false);
        }
        public void Response(int id)
        {
            IsCompleteds[id] = true;
        }
    }
    void Start()
    {
        int id = 0;
        var sampleClient = new SampleClient();
        // 毎フレームごとに処理されるので危険かも。
        var observable = Observable.EveryUpdate()
            .Subscribe(_ =>
            {
                Debug.Log("IsCompleteds.Count=" + sampleClient.IsCompleteds.Count);
                int cnt = sampleClient.IsCompleteds.Count;
                for (int tmpId = 0; tmpId < cnt; tmpId++)
                {
                    if (!sampleClient.IsCompleteds[tmpId]) continue;
                    Debug.Log("Id=" + tmpId + " sampleClient.Url=" + sampleClient.Urls[tmpId]);
                    sampleClient.IsCompleteds[tmpId] = false; // そのままにすると、連続してここが処理されるので、初期化
                }
            })
            .AddTo(gameObject);
        // 5秒後に遅延実行
        Observable.Timer(System.TimeSpan.FromSeconds(5))
            .Subscribe(_ => {
                sampleClient.Response(id);
            }).AddTo(gameObject);
    }
}