弾幕シューティングで弾を撃ちまくった 瞬間、敵がドロップしたコインが一気に湧いた瞬間——「その一瞬だけ」ガクッとフレームが落ちる。この 突発的なカクつき(スパイク) に悩まされたことはないでしょうか。
原因の多くは、オブジェクトの 生成(instantiate())と破棄(queue_free())が短時間に集中する ことです。1個の生成コストは小さくても、1秒に数百回繰り返せばCPUに無視できない負荷がかかります。これを根本から解決するのが Object Pooling(オブジェクトプーリング) です。この記事では、その仕組みから、つまずきやすい罠、弾プールの実装、そして「いつ導入すべきか」の判断までを解説します。
この記事でわかること
- スパイクの原因と、 再利用でそれを消す Object Poolingの仕組み
- 再利用時に
_ready()が呼ばれない 罠と、spawn()/reset()での初期化hide()だけでは足りない—— 処理と衝突を完全に止める 方法- 弾プールの実装と、 導入すべきかの判断 (代替手段との比較)
目次
Sponsored
Object Poolingの仕組み:使い捨てず再利用する
Object Poolingの考え方はシンプルで、 「オブジェクトを使い捨てにせず、再利用する」 だけです。レストランが皿を毎回作らず、洗って使い回すのと同じ。最もコストのかかる「生成」と「破棄」を、ゲームプレイの最中から追い出します。

動作は4ステップの循環です。
- 事前生成 :ゲーム開始時など負荷が許される場面で、一定数を生成して「プール(待機リスト)」に格納し、非表示にして おく
- 取り出し :弾を撃つなどオブジェクトが必要になったら、
instantiate()せず プールから未使用の1つを取り出して 位置を初期化し、表示する - 使用 :取り出したオブジェクトがゲーム内で役割を果たす(弾が飛んで敵に当たる)
- 返却 :役割を終えたら
queue_free()で 壊さず 、非表示にしてプールに戻す
このサイクルにより、プレイ中の負荷は「位置や状態をリセットするだけ」の軽い処理に置き換わります。結果、生成・破棄によるスパイクが消え、フレームレートが安定します。

つまずきやすい罠とベストプラクティス
Object Poolingは一見簡単ですが、いくつか落とし穴があります。特に 「再利用ならではの初期化」 が要注意です。

| よくある間違い | ベストプラクティス |
|---|---|
_ready() で初期化する | _ready() は 最初の1回しか呼ばれない 。再利用時の初期化は spawn(position, direction) のような 専用メソッド で行う |
hide() だけで戻す | hide() しても _process や衝突は動き続ける。set_process_mode(Node.PROCESS_MODE_DISABLED) で全処理を止め、CollisionShapeも無効化する |
物理中に remove_child() する | 物理演算中のツリー操作は不安定になる。call_deferred() で安全なタイミングに遅延させる |
| プールの枯渇を考えない | 激しい場面で空になると破綻する。空ならその場で生成する フォールバック + printerr で不足を検知する |
| 状態のリセット漏れ | 位置・速度だけでなく、色(modulate)・スケール・カスタム変数まで すべて初期値に戻す 。漏れは奇妙なバグの温床 |
