TrailRendererの再利用で起きる問題

TrailRendererは、オブジェクトの移動軌跡を線として描画してくれるコンポーネントです。

弾丸や魔法エフェクトなど、ObjectPoolで使い回したいケースと相性が良さそうに見えます。

ところが、プールから取り出して別の位置に移動させた瞬間、前回使ったときの終点と、今回の開始位置が1本の線で繋がってしまうという現象が起きます。

これはTrailRendererが内部に過去の頂点情報を保持していて、再有効化したときにもそれを引き継いで描画しようとするためです。

問題の起きている様子

球をObject Poolで何度も生成した様子

TrailRendererも追加した様子

このように再利用されたときに前の座標を引き継いでしまいます。

基本の対処: Clear()を呼ぶ

まず試すべきはTrailRenderer.Clear()です。

このメソッドを呼ぶと、保持している頂点情報がすべてリセットされます。

プールから取り出すタイミング、もしくはOnEnable()で呼ぶのがシンプルです。

using UnityEngine;

public class TrailReset : MonoBehaviour
{
    [SerializeField] private TrailRenderer _trail;

    private void OnEnable()
    {
        // 過去の頂点をクリアして、軌跡が繋がらないようにする
        _trail.Clear();
    }
}

多くのケースはこれで解決します。

ObjectPool経由で再利用する場合も、取得時のコールバックでClear()を呼んでおけば問題ありません。

それでも残る場合: timeを一時的に0にする

Clear()を呼んだのに線が残る、という状況に出くわすことがあります。

TrailRenderertimeプロパティで指定した秒数だけ頂点を保持する仕組みなので、フレームのタイミングによってはClear()の直後に追加された頂点が少しだけ見えてしまうのです。

この場合は、トレイルの寿命に当たる timeを一度0にしてから元の値に戻すという手順が効きます。

using System.Collections;
using UnityEngine;

public class TrailResetStrong : MonoBehaviour
{
    [SerializeField] private TrailRenderer _trail;

    private void OnEnable()
    {
        StartCoroutine(ResetTrail());
    }

    private IEnumerator ResetTrail()
    {
        // 元の time を覚えておく
        var originalTime = _trail.time;

        // 一旦 0 にして頂点を強制的に捨てさせる
        _trail.time = 0f;

        // 1フレーム待ってから元に戻す
        yield return null;

        _trail.time = originalTime;
    }
}

time0にすることで、保持されていた頂点の寿命が即座に切れます。

1フレーム待ってから元の値に戻すと、そこから新しい軌跡がきれいに描かれ始めます。

Clear()timeリセットを両方入れておくと、ほとんどの環境で軌跡の継ぎ目問題は消えます。

まとめ

TrailRendererを再利用するなら、

  • まずClear()を呼ぶ
  • それでも繋がって見えるなら、time0にして1フレーム待ってから戻す

この2段構えで対処するのが手堅いです。

プールと組み合わせる場合は、再利用時のエントリポイント(OnEnableやプールの取得コールバック)にまとめて入れておくと、

あとから他の処理を追加したときにも壊れにくくなります。