なんで作ったの
UniRxのReactiveCollectionは便利ですが、シリアライズできないのでinspectorで要素の操作をしたい時に困っちゃいます。なので、シリアライズ可能なReactiveCollectionを暫定的にでも作りたいなーと。
で、作ったのがSerializedReactiveListWrapperです。
特徴(制限)
- OnCollectionChangedをサブスクライブすることで監視状態にできます。
- OnCollectionChangedは、要素数が変化したときに発火します。
- ObserveAdd、ObserveRemoveなど細かく監視を分けてはないです。各自コード修正して頂ければ。。。
- 使えるCollectionはListだけです(今後、もっと拡張性高めたくなったらやります)
使用例
public class IntReactiveList : SerializedReactiveListWrapper<int> { }
[Serializable]
public class TestObject
{
public IntReactiveList ReactiveList => reactiveList;
[SerializeField] private IntReactiveList reactiveList = new IntReactiveList();
}
public class User : MonoBehaviour
{
//通常は別のクラスで定義して使うパターンがほとんどだろうけど、簡単のためこっちにインスタンス化。
TestObject testObject = new TestObject();
private void Start()
{
testObject.ReactiveList.ObserveCollectionChanged
.Subscribe(_ => Debug.Log("ReactiveListの変更を検知しました。"))
.AddTo(this);
}
}
SerializedReactiveListWrapper.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
[Serializable]
public abstract class SerializedReactiveListWrapper<T> : IList<T>
{
[SerializeField] protected List<T> collection = new ();
/// <summary>
/// 要素のあらゆる状況変更時に一律発行されるイベント
/// </summary>
public IObservable<Unit> ObserveCollectionChanged => observeCollectionChanged;
protected readonly Subject<Unit> observeCollectionChanged = new Subject<Unit>();
// 要素数の保存用
protected int indexCount = 0;
/// <summary>
/// 要素数が変化したら発行
/// </summary>
protected void Trigger()
{
if(indexCount != collection.Count)
{
indexCount = collection.Count;
observeCollectionChanged.OnNext(Unit.Default);
}
}
public IEnumerator<T> GetEnumerator()
{
return collection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(T item)
{
collection.Add(item);
Trigger();
}
public void Clear()
{
collection.Clear();
Trigger();
}
public bool Contains(T item)
{
return collection.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
collection.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
var result = collection.Remove(item);
Trigger();
return result;
}
public int Count => collection.Count;
public bool IsReadOnly => false;
public int IndexOf(T item)
{
return collection.IndexOf(item);
}
public void Insert(int index, T item)
{
collection.Insert(index, item);
Trigger();
}
public void RemoveAt(int index)
{
collection.RemoveAt(index);
Trigger();
}
public T this[int index]
{
get => collection[index];
set => collection[index] = value;
}
}