LoginSignup
2
0

[Unity] [UniRx] とっても便利なCompositeDisposableのお話

Last updated at Posted at 2023-12-20

はじめに

 こんにちは! Life is Tech! メンターのダイキチです。

 2023年も残りわずかとなりましたが、いかがお過ごしでしょうか?
 僕はお正月のおみくじで 大吉 を引くためにウォーミングアップを始めました。(?)

 さて、この記事は Life is Tech ! Advent Calendar 2023 の21日目の記事です。
 今回はUniRxDisposable.Create(Action disposeAction)及びCompositeDisposableについて、サンプルコードを書きながら紹介します。

Disposable.Create(Action disposeAction)を使ってみよう!

 早速ですが、Unityでカメラの追従を実装するために、カメラの親子関係を管理するCameraHandlerクラスを以下のように作ったとしましょう。

using UnityEngine;

public interface ICameraHandler
{
    /// <summary>
    /// 親子関係を構築
    /// </summary>
    /// <param name="parent"></param>
    void SetParent(GameObject parent);

    /// <summary>
    /// 親子関係を解除
    /// </summary>
    void Release();
}

public class CameraHandler : MonoBehaviour, ICameraHandler
{
    /// <summary>
    /// メインカメラ
    /// </summary>
    [SerializeField]
    private GameObject m_MainCamera;

    /// <summary>
    /// カメラを追従させる
    /// </summary>
    /// <param name="parent"></param>
    void ICameraHandler.SetParent(GameObject parent)
    {
        m_MainCamera.transform.SetParent(parent.transform);
    }

    /// <summary>
    /// カメラの追従を止める
    /// </summary>
    void ICameraHandler.Release()
    {
        m_MainCamera.transform.parent = null;
    }
}
/// <summary>
/// 利用者側のサンプルコード
/// </summary>
public class Player : MonoBehaviour
{
    private ICameraHandler m_CameraHandler;

    public void SetParent()
    {
        m_CameraHandler.SetParent(this.gameObject);
    }

    public void Release()
    {
        m_CameraHandler.Release();
    }
}

 ICameraHandler は親子関係の構築と解除のメソッドを提供しています。
 このままでも十分使えますが、ここでDisposable.Create(Action disposeAction)を使った実装に作り変えてみると、以下のようになります。

using UnityEngine;
using System;
using UniRx;

public interface ICameraHandler
{
    /// <summary>
    /// 親子関係を構築
    /// </summary>
    /// <param name="parent"></param>
    /// <returns>親子関係を解除</returns>
    IDisposable SetParent(GameObject parent);
}

public class CameraHandler : MonoBehaviour, ICameraHandler
{
    /// <summary>
    /// メインカメラ
    /// </summary>
    [SerializeField]
    private GameObject m_MainCamera;

    /// <summary>
    /// カメラを追従させる
    /// </summary>
    /// <param name="parent"></param>
    /// <returns>親子関係を解除</returns>
    IDisposable ICameraHandler.SetParent(GameObject parent)
    {
        m_MainCamera.transform.SetParent(parent.transform);
        return Disposable.Create(() => m_MainCamera.transform.parent = null);
    }
}
/// <summary>
/// 利用者側のサンプルコード
/// </summary>
public class Player : MonoBehaviour
{
    private ICameraHandler m_CameraHandler;
    
    private IDisposable m_CameraRelease;

    public void SetParent()
    {
        if (m_CameraRelease != null)
        {
#if DEBUG
            Debug.LogWarning("親子関係はすでに構築済みです。");
#endif
            return;
        }

        m_CameraRelease = m_CameraHandler.SetParent(this.gameObject);
    }

    public void Release()
    {
        m_CameraRelease?.Dispose(); // IDiposableを使って親子関係を解除
        m_CameraRelease = null;
    }
}

 主な変更点は、ICameraHandlerから提供されるメソッドがIDisposable SetParent(GameObject parent)のみになったことです。
 戻り値のIDisposableには、カメラとの親子関係を解除する処理が入っていて、これはDisposable.Create(Action disposeAction)を使って作成しています。

 こうすることで利用者側は、戻り値のIDisposableをメンバ変数で覚えておくことで、ICameraHandlerを介さずに親子関係の解除をすることができるようになりました。

CompositeDisposableを使ってみよう!

 Disposable.Create(Action disposeAction)で作成したIDisposableを戻り値にすると、利用者側に終了処理を教えることができるということが伝わったかと思います。

 しかし、実際に開発をしていると複数のIDisposableを扱いたくなるときがあります。そんなときはCompositeDisposableを使いましょう。

/// <summary>
/// 利用者側のサンプルコード
/// </summary>
public class Player : MonoBehaviour
{
   private ICameraHandler m_CameraHandler;
   private IDummyHandler m_DummyHandler;
   
   private CompositeDisposable m_CompositeDisposable = new CompositeDisposable();

   public void SetParent()
   {
       var cameraDisposable = m_CameraHandler.SetParent(this.gameObject);
       m_CompositeDisposable.Add(cameraDisposable);// IDisposableを登録

       var dummyDisposable = m_DummyHandler.DummyMethod();
       m_CompositeDisposable.Add(dummyDisposable); // IDisposableを登録
   }

   public void Release()
   {
       m_CompositeDisposable.Clear(); // IDisposableをまとめてDispose
   }
}

 void Add(IDisposable item)IDisposableCompositeDisposableに登録できます。
 また、void Clear()で登録したIDisposableをまとめてDisposeできます。このとき、登録されていたIDisposableは全て破棄されます。

おわりに

 今回は UniRxDisposable.Create(Action disposeAction)及びCompositeDisposableについて紹介しました。

 細かい説明は端折って解説してしまったので、より詳しいことを知りたい方はこの後に載っている参考文献をお読みください。

 さて、明日の Life is Tech ! Advent Calendar 2023みったに先生の記事になります。
 どうやらUI演出についての記事のようです。楽しみですね!!

 以上、Life is Tech! メンターのダイキチでした。またね〜!

参考文献

2
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
2
0