Qemelly(けめる)のプログラム備忘録

Unity / AtCoderについて書きます

【UniRx】AsyncSubjectで初期化の順番を分かりやすく記述する

初期化処理ってとにかく順番が命で、ちょっとでもミスるとエラーまみれになってしまいがちです。特にロードしきれてないのに呼び出しちゃってnull参照エラーになることはよくあります(あるな)。

最近Awake()やStart()がテキトーに呼ばれているという事実を目の当たりにし、ちゃんと初期化処理書かないと痛い目見るな...となったのですが、あまりいい方法が分からず。

一応下記ブログのようにしてStart()の実行順序を変えることもできるのですが、結構面倒だし、動的に生成されるものについても考えると大変です(方法として知っておくのは大事だけど)。 bluebirdofoz.hatenablog.com  

というわけで、本題。

AsyncSubject

参考記事↓

qiita.com

www.hanachiru-blog.com

UniRxの機能であるAsyncSubjectは、OnComplete時に最後にOnNextされた値のみを発行するSubjectです。普通のSubjectとは違い、機能が限定されている分、目的が明確になって分かりやすく初期化処理を書くことが出来ます。

以下に初期化の例を記述します。

public class Player : MonoBehaviour
{
    // 初期化が終わったかを監視するSubject
    public IObservable<Unit> OnInitializeAsync => _onInitializeAsyncSubject;
    private readonly AsyncSubject<Unit> _onInitializeAsyncSubject = new();

    private void Awake()
    {
        // Playerの初期化処理(ステータス、各種GetComponentなど)

        // Awakeの最後にOnNextとOnCompletedを発行
        _onInitializeAsyncSubject.OnNext(Unit.Default);
        _onInitializeAsyncSubject.OnCompleted();
    }
}
public class SomethingPlayerComponent : MonoBehaviour
{
    private Player _player;

    private void Start()
    {
        _player = GetComponent<Player>();

        // Playerの初期化が終わったらOnPlayerInitialized()を実行する
        _player.OnInitializeAsync
            .Subscribe(_ => OnPlayerInitialized());
    }

    private void OnPlayerInitialized()
    {
        // Playerが初期化されているのでPlayerから何かを取得してもnull参照にならない(初期化で不足がある場合を除く)
    }
}

Playerクラスにて各種コンポーネントの取得等の初期化処理をしたとき、コンポーネント側で初期化を待てるようにしたい、という場合が多くあると思います。 そういった際にはうってつけだと思うので是非。

(なんかでももっといい機能ありそうなんだよな...)