👇 コチラの Unity MonoBehaviour
対応版。
つかいかた
Unity の事情に合わせたので少し特殊。メインスレッドからしか呼べません。
※ 必要な GameObject
は Rent
すると勝手に作られます。
public class MyBehaviour : PoolableBehaviour<MyBehaviour> // 👈
{
// オーバーライドの必要ナシ。継承すれば動く
}
// 貸出時に GameObject を有効化するか選ぶ。false なら Awake, OnEnable, Start は実行されない
var component = MyBehaviour.Rent(activateGameObject: false, parent: null);
component.InitializeBeforeActivate();
component.gameObject.SetActive(true);
// 任意のタイミングで返却。または CancellationToken への紐づけ
component.ReturnToPool();
component.ReturnToPoolIfCanceled(otherComponent.destroyCancellationToken);
// いわゆる Warmup メソッド。インスタンス化だけでなく Awake 等も事前に実行しておきたいならパラメーターで指定する
MyBehaviour.Populate(count: 10, true);
// プールに残す未使用インスタンス数を指定して溢れたものは削除する(OnDestroy が実行される)
// ※ 貸し出し中のインスタンスは数に含まれない
MyBehaviour.TrimExcess(3);
メニューコマンド
Unity エディター > DEBUG > Poolable Behaviour
から各種テストが可能。
TODO/各種仕様
プレハブをプーリングしたい
PoolableBehaviour
を継承し「Awake
メソッドでプレハブをインスタンス化して抱える」コンポーネントとして実装すれば実現できると思います。
※ プールに残っている未使用インスタンスを探して存在しなかったらプレハブから持ってくる、という実装は必要ありません。どのようなリソースもプーリング可能な MonoBehaviour に管理を委ねれば間接的にプールの管理下に入ることになります。
プレハブに PoolableBehaviour
が含まれる場合
貸し出された Poolable インスタンスは完全にプールの管理下から外れます。これは AddComponent
メソッドで追加したり、Unity エディターのインスペクターでマウスを使ってアタッチしたときと同じ状態です。
プレハブに含まれる Poolable は「貸し出されてプール管理下から外れた」状態のインスタンスです。なので、何もしなければ普通のコンポーネントと同じ振る舞いをします。
Poolable のインスタンス再利用に必要なのは「
ReturnToPool
を実行すること」です。実行しなかった場合は普通のコンポーネントと同じ挙動を示します。なので、親 Transform やシーンが削除されれば巻き込まれて消えます。※ インスタンスをプールに返却し損ねても特にペナルティーはありません。
プール返却時の階層構造
- PoolableA
- PoolableB
- PoolableC
- NonPoolableComponent
- PoolableB
このような階層構造で PoolableA.ReturnToPool()
を実行すると、B
C
もプールに返却されます。つまり、階層構造が維持されずフラットになります。ただし Poolable ではない NonPoolableComponent
は A
の階層に残ります。
貸出時の挙動をカスタマイズしたい
Rent
メソッドにオーバーロードを追加します。シグネチャが同じなら new
します。
// 引数無しで常に良い感じにするメソッドに出来ないならカスタマイズしなくて良い
public static MyBehaviour Rent()
{
var result = Rent(false, parent: appropriateTransform);
result.AwesomeSetup();
result.gameObject.SetActive(true);
return result;
}
// new 宣言を Obsolete して戻り値の型を変えておけば元のオーバーロードが間違って使われるのを防げる
// Rent() 内では継承元のメソッドを直接呼んで迂回する → PoolableBehaviour<MyBehaviour>.Rent(true);
[Obsolete("Use Rent() instead", true)]
new public static void Rent(bool x, Transform? y = null, bool z = true)
=> throw new NotImplementedException();
返却時/削除時の挙動をカスタマイズしたい
OnDisable
OnDestroy
を実装します。別の方法でカスタマイズした場合、親 Transform やシーンに巻き込まれて削除された時の動作を保証できません。
Rent
を使わずに Poolable を GameObject にアタッチした場合
多分動きます。
複数の PoolableBehaviour
をひとつの GameObject にアタッチした場合
動く気がします。
ソースコード
--
サクッと作れるかと思ったら意外と大変でした。
以上です。お疲れ様でした。