0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UniRxのReactiveCollectionがシリアライズできないので作ったクラス SerializedReactiveListWrapper

Last updated at Posted at 2023-06-27

なんで作ったの

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;
    }
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?